|
I have used and implemented them before. I've been doing .net since 2002. I'm just saying they're strange from a language design perspective. I'm not dissing them. I'm not dissing you. I just think they are an odd design decision on the part of the original language creators. I know they come from java, and that's fine. I know they have their uses. While I did say "hardcoded" I should have said "single pathed" because the presence of one or more or many or no attribute is an open ended scenario. I didn't meant it was somehow dynamic, and I don't have a lack of understanding for what they are. I still don't agree that they fit, from a design of the language(s) perspective.
|
|
|
|
|
I think I get what you're trying to say. I guess you have a point about not fitting in a traditional OOP perspective. In some ways they resemble a dynamic language but there's where we get philosophical about the matter.
When that happens, its about everyone's opinion. Are they worth it? I'd say definitely yes. Some might say no. But I'm glad I have the option.
In the other hand, the introduction of the dynamic keyword on framework 4 to me it is not worth it. It creates a range of bad practices that might end up on your lap someday when you inherit a project. Attributes on the other hand are more obscure to beginners and as such have less probability to have bad and mysterious code along.
.Net is evolving and it's setting ground on foreign lands. I think it's a good thing as of now, as long it doesn't stretch too much out of its purpose. There's always going to be things that are fit for some and ugly for others. I can just hope that .net does not become an over crumbled platform.
"To alcohol! The cause of, and solution to, all of life's problems" - Homer Simpson
|
|
|
|
|
Definitely agree about the dynamic keyword... but I'll just opt out of using it, at least until someone changes my mind about that. Maybe they will.
|
|
|
|
|
Yep, me too. But they can be useful when doing some COM interop though.
"To alcohol! The cause of, and solution to, all of life's problems" - Homer Simpson
|
|
|
|
|
dave.dolan wrote: like configuration is supposed to be
So write Attributes that read the configuration.
(Darn, now I have to contrive an example... )
[Later] And so I wrote...
using Prop=System.Collections.Generic.KeyValuePair<System.Reflection.PropertyInfo,object> ;
using Proptionary=System.Collections.Generic.Dictionary<System.Reflection.PropertyInfo,object> ;
public class ConfigValueAttribute : System.ComponentModel.DefaultValueAttribute
{
private static readonly System.Collections.Generic.Dictionary<string,System.Xml.XmlDocument> doc ;
private static readonly System.Collections.Generic.Dictionary<System.Type,Proptionary> typ ;
static ConfigValueAttribute
(
)
{
doc = new System.Collections.Generic.Dictionary<string,System.Xml.XmlDocument>() ;
typ = new System.Collections.Generic.Dictionary<System.Type,Proptionary>() ;
return ;
}
public ConfigValueAttribute
(
string ConfigFilePath
,
string XPath
)
: base
(
null
)
{
string fil = System.Environment.ExpandEnvironmentVariables ( ConfigFilePath ) ;
if ( !doc.ContainsKey ( fil ) )
{
System.Xml.XmlDocument temp = new System.Xml.XmlDocument() ;
temp.Load ( fil ) ;
doc [ fil ] = temp ;
}
System.Xml.XmlNode nod = doc [ fil ].SelectSingleNode ( XPath ) ;
if ( nod is System.Xml.XmlAttribute )
{
this.SetValue ( nod.Value ) ;
}
else
{
this.SetValue ( nod.InnerText ) ;
}
return ;
}
public static T
Apply<T>
(
T Source
)
{
System.Type t = typeof(T) ;
if ( !typ.ContainsKey ( t ) )
{
Proptionary props = new Proptionary() ;
foreach ( System.Reflection.PropertyInfo pi in t.GetProperties() )
{
foreach ( ConfigValueAttribute att in pi.GetCustomAttributes ( typeof(ConfigValueAttribute) , false ) )
{
props [ pi ] = att.Value ;
}
}
typ [ t ] = props ;
}
foreach ( Prop prop in typ [ t ] )
{
try
{
prop.Key.SetValue
(
Source
,
System.Convert.ChangeType
(
prop.Value
,
prop.Key.PropertyType
)
,
null
) ;
}
catch
{
/* Leave it at the default */
}
}
return ( Source ) ;
}
}
public class SomeClass
{
[ConfigValueAttribute("ConfigValueAttributeTest.xml","/ConfigValueAttributeTest/StringValue")]
public string StringValue { get ; private set ; }
[ConfigValueAttribute("ConfigValueAttributeTest.xml","/ConfigValueAttributeTest/StringValue/@AttValue")]
public string AttValue { get ; private set ; }
[ConfigValueAttribute("ConfigValueAttributeTest.xml","/ConfigValueAttributeTest/NumValue")]
public int IntValue { get ; private set ; }
[ConfigValueAttribute("ConfigValueAttributeTest.xml","/ConfigValueAttributeTest/NumValue")]
public double DoubleValue { get ; private set ; }
public SomeClass
(
)
{
ConfigValueAttribute.Apply ( this ) ;
return ;
}
}
SomeClass x = new SomeClass() ;
System.Console.WriteLine ( "StringValue = {0}" , x.StringValue ) ;
System.Console.WriteLine ( "AttValue = {0}" , x.AttValue ) ;
System.Console.WriteLine ( "IntValue = {0}" , x.IntValue ) ;
System.Console.WriteLine ( "DoubleValue = {0}" , x.DoubleValue ) ;
<ConfigValueAttributeTest>
<StringValue AttValue='ATAT' >Test</StringValue>
<NumValue>3.14</NumValue>
</ConfigValueAttributeTest>
modified 22-Oct-11 10:27am.
|
|
|
|
|
|
Yep, on my first contact with them I thought: "How does this magic happen?". But then when you figure the fun about the way they work.
"To alcohol! The cause of, and solution to, all of life's problems" - Homer Simpson
|
|
|
|
|
Most of my custom Attributes are for use with enumerations.
I don't use many of the built-in Attributes because I don't write the kinds of applications that they're designed for.
modified 18-Oct-11 8:57am.
|
|
|
|
|
I second it!, however i used in-built attributes only, never made one or you can say it's too complicated for VC++ programmer like me
"Opinions are neither right nor wrong. I cannot change your opinion. I can, however, change what influences your opinion." - David Crow Never mind - my own stupidity is the source of every "problem" - Mixture
cheers,
Alok Gupta
VC Forum Q&A :- I/ IV
Support CRY- Child Relief and You
|
|
|
|
|
ok so having never used them before I had to solve my curiosity... unfortunately MSDN wasn't very helpful. so aside from the examples that MSDN gave can anyone else site some real world example where Attributes would be used??
|
|
|
|
|
A webservice is implemented as a class like any other. It can have many methods, but not all should be exposed as webmethods of the service. That's why you decorate the class itself with the 'webservice' attribute to specify that this class will act as a webservice and exposes webmethods. And only those methods wich are supposed to become webmethods get the 'webmethod' attribute. When the webservice is compiled, the attributes are being read and the classes and methods with those attributes will be used to generate the service description and the code to access the webservice.
When you write your own controls, you can use attributes to show or hide them from the Visual Studio toolbox or determine which ones of the control's properties appear in the properties window.
When you intend a class for serialisation, you can use attributes to control which properties and public members are serialized and which are not.
Or, more general, attributes are simple data objects which give another class (which reads the attributes via reflection) information on how to use the class or its methods, properties or member variables. You can even write your own attributes for some purpose, but they will be of little use unless you write another class which looks for and uses those attributes when objects are passed as parameters.
And from the clouds a mighty voice spoke: "Smile and be happy, for it could come worse!"
And I smiled and was happy And it came worse.
|
|
|
|
|
great example of how they are already being used.
I guess what I was more curious about is an example of where I would want to develop my own attributes. I liked your example of it being used with reflection and to be honest I never gave this any thought with reflection.
would love to see an article talking about Attributes and using them in reflection. anyone care to shamelessly promote their article??
|
|
|
|
|
At work, we use a code generation utility and framework to automatically generate C# proxys for unmanaged C++ objects. We use attributes to detemine which properties/methods/classes from the C# interfaces bind to which underlying C++ methods/classes, etc. The generator produces the implementation automagically from the interface declarations.
I also used attributes for determining the design time behavior of custom controls in custom designers in WinForms.
|
|
|
|
|
Hi Dennis,
I've been using attributes extensively in nearly all my business objects for quite a while now and I find them to be most useful for general validation and integrity checks. I have a series of attributes that are purely business object related and these in turn help to reduce the repetitive nature of business objects and the general bloat of validation code.
Business object property validation[^]
An example of a custom attribute would be as follows:
Option Strict Off
Option Explicit On
Imports System.Reflection
Namespace Attributes
<AttributeUsage(AttributeTargets.Field Or AttributeTargets.Property)> Public Class NotEmptyAttribute
Inherits attribBase
Implements ITest
Private mstrDependantPropName As String
Public Sub New(Optional ByVal strDependantPropName As String = "")
mstrDependantPropName = strDependantPropName
End Sub
Public Function GetRule() As String Implements ITest.GetRule
Return "The value cannot be a zero length (empty) string"
End Function
Public Function TestCondition(ByVal Value As Object, ByRef cls As Object) As Boolean Implements ITest.TestCondition
If Value Is Nothing Then Return True
Dim lStr As String = CType(Value, String)
If Not lStr.Equals(String.Empty) Then Return False
If mstrDependantPropName.Equals(String.Empty) Then
Return True
End If
Dim lStrPropType As String = String.Empty
Dim lObjVal As Object = Nothing
If SetLocalObjects(mstrDependantPropName, cls, lStrPropType, lObjVal) = False Then Return False
Return TestDependant(lStrPropType, lObjVal)
End Function
End Class
End Namespace
As you can this attribute inherits from a base class:
Option Strict Off
Option Explicit On
Imports System.Reflection
Namespace Attributes
<AttributeUsage(AttributeTargets.Field Or AttributeTargets.Property)> Public Class attribBase
Inherits System.Attribute
Protected Overridable Function SetLocalObjects(ByVal propName As String, ByRef cls As Object, ByRef strPropType As String, ByRef objVal As Object) As Boolean
Dim t As Type = cls.GetType
Dim m As System.Reflection.MemberInfo() = t.GetMember(propName)
If m.Length < 1 Then Return False
Dim pi As PropertyInfo
Dim fi As FieldInfo
If TypeOf m(0) Is PropertyInfo Then
pi = t.GetProperty(propName)
strPropType = pi.PropertyType.ToString
objVal = pi.GetValue(cls, Nothing)
Else
fi = t.GetField(propName)
strPropType = fi.FieldType.ToString
objVal = fi.GetValue(cls)
End If
Return True
End Function
Protected Overridable Function TestDependant(ByVal strPropType As String, ByVal objVal As Object) As Boolean
Select Case strPropType
Case GetType(Boolean).ToString
If CType(objVal, Boolean).Equals(False) Then Return False
Case GetType(DateTime).ToString
If CType(objVal, DateTime).Equals(DateTime.MinValue) Then Return False
Case GetType(String).ToString
If CType(objVal, String).Equals(String.Empty) Then Return False
Case GetType(Guid).ToString
If CType(objVal, Guid).Equals(Guid.Empty) Then Return False
Case GetType(Int32).ToString
If CType(objVal, Int32).Equals(CType(0, Int32)) Then Return False
Case GetType(Int16).ToString
If CType(objVal, Int16).Equals(CType(0, Int16)) Then Return False
Case GetType(Byte).ToString
If CType(objVal, Byte).Equals(CType(0, Byte)) Then Return False
End Select
Return True
End Function
End Class
End Namespace
Hope this helps...
Edward Steward
edwardsteward@optusnet.com.au
|
|
|
|
|
Here's an example of the use of a custom Attribute: EnumTree[^]
|
|
|
|
|
Orm Mapping e.g.
[Table("MyFooTable")]
{
[Column("ColumnName", DbType.Varchar, 255)]
public string Bar {get; set}
[Column]
public string Baz {get; set}
}
The above psuedocode pretty much, but I have seen it done like this. There are similar things for serialization. You should try googling for ".net data annotations" - these are really useful for UI work.
|
|
|
|
|
See my real world example:
It's awesome when you figure its power
"To alcohol! The cause of, and solution to, all of life's problems" - Homer Simpson
|
|
|
|
|
Localization tools for WPF applications are crap, so I had to roll my own. I use a custom attribute to mark translatable properties in my custom controls. I may eventually enhance my attribute to support passing useful information to my localization tool for display to the translators.
Software Zen: delete this;
|
|
|
|
|
Interesting. I'm writing a GUI for XNA and don't have any concept for localization yet. You have not written an article about this?
And from the clouds a mighty voice spoke: "Smile and be happy, for it could come worse!"
And I smiled and was happy And it came worse.
|
|
|
|
|
Not yet. I'll give it some thought.
Software Zen: delete this;
|
|
|
|
|
Data annotations are a peach, as are the ones to secure the action methods on controllers.
I very rarely hand-roll my own anymore, even those were either for serialization or (once) to create my own ORM framework in lieu of the EF being supported. I'm thinking of creating one so I can secure action methods decorated with it form the database, but for now I'm KISSing it.
|
|
|
|
|
If you are referring to custom attributes, then I have never used any. If you are referring to built-in attributes (.Net or third party controls, dlls) then all the code I have written so far uses them.
"The worst code you'll come across is code you wrote last year.", wizardzz[ ^]
|
|
|
|
|
There are only three reasons I use attributes:
1. XML Serialization
2. Designer info used by the property grid
3. Metadata describing how my plugins intercept SQL transactions
The third isn't necessary and may eventually be replaced with a standard plugin API call to discover the desired behavior rather than using reflection.
I used to think that attributes were the cat's meow. After using them extensively, I discovered that they are just another layer of obfuscation that complicates the maintenance of the code. I realized that a much better implementation would have been to keep the the imperative code separate from the metadata declarative portions. As it stands, the source code combines both. What I think would be better is a separate, purely declarative, repository as a map of the imperative code and the desired attributes. This would have allowed the attributes to vary independently from the code. Consider changing a serialization attribute, like the XML attribute name, or a description of a property to assist the form designer. Good grief, I have to touch the code base to do that? Absurd, in my opinion.
So that's what I've learned over the years, is that the code and the attributes should actually have been kept physically separate.
Marc
|
|
|
|
|
Hmm, the classes used to hold attributes are very simple data containers. They have the advantage that you can declare, change and inherit them as you need them, also including own types if it must be. Also, seen from a framework developer's view, they are never modified. Deprecated and replaced by another perhaps, but not simply changed.
And from the clouds a mighty voice spoke: "Smile and be happy, for it could come worse!"
And I smiled and was happy And it came worse.
|
|
|
|
|
Marc Clifton wrote: After using them extensively, I discovered that they are just another layer of
obfuscation that complicates the maintenance of the code
Isn't it always this way with coding "conveniences"? People think their code is better when they use the latest/greatest language/framwork feature, but all it serves to do is to confuse new people working on a given project, and hopelessly slows down orientation of rookie programmers. I don't even use lamdas a lot, and for the very same reason. I only use attributes in very rare instances - when they're required, and for nothing more. On a semi-related note, I try to avoid using reflection whenever possible as well.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass." - Dale Earnhardt, 1997
modified 17-Oct-11 12:38pm.
|
|
|
|
|