|
|
Comments and Discussions
|
|
 |

|
Easy to understand example and talked about the framework that allows this.
|
|
|
|

|
How can I Add Atrribute to my custom class (inherit from Attributes) ?
thanks
|
|
|
|
|
|

|
HI,
i want to read custom .net attributes from the configuration file and incorporate that attribute to the method in my code.
for example
in my .config file i have like this
EventSubscription("topic://CabPoc/ViewOrder")
i want to incorporate this as below
[EventSubscription("topic://CabPoc/ViewOrder")]
public void OnViewOrder(object sender, DataEventArgs> e)
{
ShowOrder(e);
}
any help please
Thanks in advance
Narasimha
|
|
|
|

|
Thanks for a great article, very concise and clear. I have just started using attributes pretty extensively and thiw was very helpful.
Do you know of a way to define and apply attributes at RunTime. I am extending a control in VB.Net and have serialized certain properties of that control so that the developer can configure their own default settings. But the DefaultValue attribute only takes a constant value. I have been trying to figure out a way to apply them after the fact to the configuarable properties so that the Property browser at DesignTime properly shows their choices unbolded.
Any ideas or suggestions would be greatly welcomed. Feel free to contact me at the signature line below. Thanks again for a nice article!
Have a great day!
j2associates_NO_SPAM_@yahoo.com
|
|
|
|

|
The designer will look for some specially named methods in your Form/Control class to allow you to do this type of thing: void ResetMyProperty() and bool ShouldSerializeMyProperty(). This applies to both .NET 1.x and 2.0
ShouldSerialize should return true in the event that the current value is not equal to the value the property will have upon control creation. Reset will be called when the user chooses the reset option on the context menu. That option will only be available when ShouldSerialize returns true.
Now if you are really intent on using attributes, and are able to use .NET 2.0 read on...
In .NET 2.0 you can inherit from the DefaultValueAttribute class to change how it works. [In .NET 1.x the DefaultValueAttribute class is sealed, and thus you can't inherit from it]
Rather than pass in a constant value representing the default; you could pass in a value to uniquely identify the control (for example the form name and name of the control).
For example (untested code):
using System;
using System.ComponentModel;
public class MyDefaultValueAttribute : DefaultValueAttribute
{
private string id;
public MyDefaultValueAttribute( string id ) : base( null )
{
this.id = id;
}
public override object Value
{
get {
}
}
}
Now if you use your new attribute instead of the one from the framework you should get your defaults to show up. I don't know how well this will play with the designer though; for example if your default changes while the control is loaded in the designer the new default may not show until the form is reopened...or worse when the solution is closed and reopened.
HTH,
James
|
|
|
|

|
Thanks for your reply, it was helpful and just repointed me in the direction I need to go. I was already using ResetPropName and ShouldSerializePropName elsewhere in the project.
The biggest headache I was having was getting properties based on enumerations to work. It appears that <> with enumerations is inconsistent, at least within Reset and ShouldSerialize. When I replaced them with the following code they began to work:
If Not myVar.Equals(Value) Then
'Do Something
End If
Have a great day!
j2associates_NO_SPAM_@yahoo.com
|
|
|
|

|
i defined an attribute like this:
//set the Inherited property with 'true'
[AttributeUsage(AttributeTargets.All,Inherited=true,AllowMultiple = false)]
public class MyAttribute : Attribute {}
then use the attribute ——
public class BaseClass
{
[MyAttribute]
public virtual int Property{...}
}
public class MyClass : BaseClass
{
public override int Property{...}
}
then i get the attributes length of 'Property' in 'MyClass'——
int len = typeof(MyClass).GetProperty("Property").GetCustomAttributes(true).Length;
print len,value is 0(i hope it will be 1),it's show that the 'Inherited' property of AttributeUsageAttribute can not use to the property of class.
And How Can i retain the property's attribute of baseclass?
thanks to help me !!
|
|
|
|

|
Hi,
I'm planning to use Authorization and Profile Application Block for my application's access control. Access check need to be performed in each method call to ensure user has the right permission, like:
Public void MyMethod()
{
...
principal.AuthorizationParameters.Add("operations", new string[1]{"My operation name"});
if (!principal.AccessCheck())
throw new PermissionException("Permission Denied");
...
}
It would be nice if I can implement this using declarative style, like the .NET framework's declarative security, such as:
[OperationPermission("My operation name")]
Public void MyMethod()
{
...
}
Can somebody help on this?
Thanks
|
|
|
|

|
Hi James,
Is it possible to use attributes to control whether a class inherited from Form appears in designer? I have a base class which inherits from Form and implements only non-visual functionality. Therefore, I want to be able to edit the code in the IDE editor but not in the designer. And, to make things more complicated, I don't want this restriction for forms that inherit from the base class.
thanks
|
|
|
|
|

|
I have written an exported DLL that I call from C#. Some of the methods take/return a SAFEARRAY *. The DLL creates the SafeArray using SafeArrayCreateVectorEX. My DLLImport statement specifies the following
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
public static extern byte [] MyFunc();
and I am declaring the return type as a byte []. When the function returns, it appears that I have a valid byte array. But who cleans up the SAFEARRAY*? Does the marshaller take care of this? Or do I somehow need to specify to the DLL to destroy the SAFEARRAY*?
Along the same lines, my DLL takes BSTR parameters. I have been converting my strings to IntPtr using Marshal.StringToPTr method, I pass in the IntPtr, and when I return, I use Marshal.FreeBSTR to clean up the IntPtr. This way, I know I am cleaning up the BSTR. If I were to delcare my method specifying to MarshalAs BSTR, so that I won't have to do the conversion manually, who would clean up that BSTR? The Marshaller, or would I have to call SysFreeString on the inside of the DLL?!
I have looked around the internet and the Help files for an answer but to no avail. Micro$oft just doesn't specify where the clean up must be done and by who?
Any help is *GREATLY* appreciated!
|
|
|
|

|
Okay, it is possible to match an AttributeUsage only to fields with the help of AttributeTargets enum. But what can I do to fix a special attribute only on fields which data type is for instance a string? Is it possible? Have you a piece of code to verify that?
Many thanks.
|
|
|
|

|
Dr. Heiko Voß wrote:
But what can I do to fix a special attribute only on fields which data type is for instance a string?
There isn't much you can do at compile time, but at run time you can check the FieldInfo's MemberType property to see if it is the correct type.
public bool VerifyAttributeIsOnString(FieldInfo fi)
{
MyAttribute [] myAttributes =
(MyAttribute[]) fi.GetCustomAttributes(typeof(MyAttribute));
if( myAttributes != null && myAttributes.Length > 0 )
{
if( fi.MemberType == typeof(string) )
{
return true;
}
else
{
return false;
}
}
return false;
}This is untested but it should work.
If you want the attribute to be applied to object Types that aren't sealed (ie it is legal to create a new class deriving from the class you want to restrict the Attribute to) then you should replace fi.MemberType == typeof(string) with fi.MemberType.IsInstanceOfType( typeof(MyClass) ). This allows the attribute to be applied to fields of type MyClass as well as MyDerivedClass.
HTH,
James
At Jethro Tull's August 28, 2003 concert Ian Anderson mentioned that the group would be performing a medley of title tracks. The songs were "Songs from the Wood", "Too Old to Rock and Roll; Too Young to Die"; and from the Heavy Horses album, "Stairway to Heaven".
|
|
|
|

|
Another option available is to extend "eXtensible C#" and have it analyze the code so that it catches those errors during XC#'s second compile step.
eXtensible C#[^]
Doing so might not be easy, but it can change the debugging from run-time to compile-time.
James
At Jethro Tull's August 28, 2003 concert Ian Anderson mentioned that the group would be performing a medley of title tracks. The songs were "Songs from the Wood", "Too Old to Rock and Roll; Too Young to Die"; and from the Heavy Horses album, "Stairway to Heaven".
|
|
|
|

|
Hai,
I found your article extremely informatiive and useful. I was on the lookout for an article that could explain custom Attributes. However, I came across an error when I started applying it into my VB.NET project. I'm trying to marshal an array from .NET To ASP and wanted to apply a MarshalAsAttribute to the variable array that I declared. Following is my definition of the variable:
Private arrObjects()
The above definition gives me a compile time error, "Constant Expression is Required" and it underlines "SafeArraySubType".
I have imported the System.Runtime.InteropServices.VarEnum and also the System.Runtime.InteropServices.MarshalAsAttribute classes. Any clues on how I could get this working would be of great help.
Thanks again for sharing your knowledge
regards,
Chris
|
|
|
|

|
When you need to modify additional variables in an attribute you need to use what VB calls named parameters:
In this case the correct code would be:
<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_VARIANT)> _
Private myarr() As Object Notice that between the property name and the value you use :=, not just = as C# uses. This tells VB that the argument named 'SafeArraySubType' is to receive the value of 'VarEnum.VT_VARIANT' and leave the other arguments at their default value.
Here is a point where C# and VB differ, C# doesn't allow method parameters to have default values, so they created the extended syntax where you act like you are setting a property. VB on the other hand DOES allow method parameters to have default values so it treats Attributes as having one (or several) large constructors with default parameters. Hence, why you need to use the named parameters method.
HTH,
James
At Jethro Tull's August 28, 2003 concert Ian Anderson mentioned that the group would be performing several songs in a row and that they were all title tracks. The songs were "Songs from the Wood", "Too Old to Rock and Roll; Too Young to Die"; and from the Heavy Horses album, "Stairway to Heaven"
|
|
|
|

|
James,
Thanks so much for the response. I actually have been struggling for an entire day to get this syntax right!.
I have yet another issue, I'm actually working on an interop project and trying to marshal arrays from VB.NET To ASP. Thats where I'm explicitly using these attributes. I'm getting type mismatch if I use the SafeArray with the MarshalAs Attribute and on the other hand I'm able to retrieve the array values in VB if I use LPArray. But there seems to be a distinctive problem, early binding in VB does not show the functions that return the array, and thats becuase Regasm /tlb utility generates warnings for Arrays marshalled using LPArray and ASP, although retrieves Array, but is unable to loop through and returns type mismatch if looped through.
Any ideas how I could marshal an array of objects from VB.NET To ASP and to VB.
Thanks for all the help, really appriciate your effort.
regards,
Chris
|
|
|
|
|

|
Hi
I have some problem maybe you can help me
I define some attribute and implemented in MyClass:
[Categories("CatMain","this is CatMain Description")]
public class AttributeTest
{
public AttributeTest(){}
[Categories("Cat1","this is Cat1 Description")]
public class CategoryTest
{
public CategoryTest(){}
[Template("Cat1-Temp1","this is Tem1 of Cat1")]
public class TemplateCat1
{
public TemplateCat1(){}
}
}
}
I can’t get my attribute when I search for them. My code looks like this:
Object[] attrs = typeof(AttributeTest).GetCustomAttributes(true);
The result of this code is:
Attrs = length = 1
Why????
Why didn’t I get all Attribute?
Isn't Attrs should be length = 3????
Thanks
|
|
|
|

|
Danny Keynan wrote:
Why didn’t I get all Attribute?
Type.GetCustomAttributes will only return the attributes defined on the type member you used it on.
So when you call it on the Type representing a class it will return the attributes applied to the class. When you call it on the MethodInfo object representing a particular method, it will return the attributes applied to that method.
To retreive them all you can use a recursive method to get them all. A short example follows, as compiled by CodeProject (in other words, I'm winging it so there may be syntax or minor logic errors):
public ArrayList GetCustomAttributes(Type typeToSearch)
{
ArrayList al = new ArrayList();
al.AddRange(typeToSearch.GetCustomAttributes(true));
Type [] nestedTypes = typeToSearch.GetNestedTypes();
foreach(Type nType in nestedTypes)
{
al.AddRange( GetCustomAttributes(nType) );
}
return al;
}HTH,
James
"It is self repeating, of unknown pattern"
Data - Star Trek: The Next Generation
|
|
|
|

|
Thanks it’s was very helpful
Danny
|
|
|
|

|
Hi James
I have another question about the custom attribute.
Let’s say that I have the same class:
[Categories("CatMain","this is CatMain Description")]
public class AttributeTest
{
public AttributeTest(){}
[Categories("Cat1","this is Cat1 Description")]
public class CategoryTest
{
public CategoryTest(){}
[Template("Cat1-Temp1","this is Tem1 of Cat1")]
public class TemplateCat1
{
public TemplateCat1(){}
[Parameter("DefaultValue")]
public string myString;
}
}
}
And i did recursive search for my custom attribute like you said:
public ArrayList GetCustomAttributes(Type typeToSearch)
{
ArrayList al = new ArrayList();
al.AddRange(typeToSearch.GetCustomAttributes(true));
Type [] nestedTypes = typeToSearch.GetNestedTypes();
foreach(Type nType in nestedTypes)
{
al.AddRange( GetCustomAttributes(nType) );
}
return al;
}
Now I have information according to the reflaction field type on
[Parameter("DefaultValue")]
public string myString;
And now for my question:
How do I set the value of myString using the reflection type?
|
|
|
|

|
Danny Keynan wrote:
How do I set the value of myString using the reflection type?
First we need to expand the GetCustomAttributes method a bit so we can do it:
class CustomAttributeInstance
{
public readonly Attribute Attribute;
public readonly MemberInfo AppliedTo;
public CustomAttributeInstance(Attribute a, MemberInfo apTo)
{
this.Attribute = a;
this.AppliedTo = apTo;
}
}This is just a helper that stores a reference to the attribute instance as well as what the attribute was applied to.
public ArrayList GetCustomAttributes(Type typeToSearch)
{
ArrayList al = new ArrayList();
object [] attrs = typeToSearch.GetCustomAttributes(true));
foreach(object oAttr in attrs)
{
Attribute attr = oAttr as Attribute;
if( attr != null )
{
al.Add( new CustomAttributeInstance(attr, typeToSearch) );
}
}
Type [] nestedTypes = typeToSearch.GetNestedTypes();
foreach(Type nType in nestedTypes)
{
al.AddRange( GetCustomAttributes(nType) );
}
return al;
}Now that we've modified the method we can put that added information to use.
public void SetValue(
CustomAttributeInstance cai, object instance,
object value
)
{
Attribute a = cai.Attribute;
MemberInfo mi = cai.AppliedTo;
FieldInfo fi = mi as FieldInfo;
PropertyInfo pi = mi as PropertyInfo;
if( !(fi == null) && !(pi == null) )
{
throw new ArgumentException("cai", "The MemberInfo doesn't reference a field or a property");
}
else if( pi != null && !pi.CanWrite )
{
throw new ArgumentException("cai", "The MemberInfo references a read-only property");
}
if( fi != null)
{
fi.SetValue(instance, value);
}
if( mi != null)
{
pi.SetValue(instance, value, null);
}
}To use this, you pass in the CustomAttributeInstance obtained from the GetCustomAttributes method above as well as the instance of the class* and the new value.
Well, I didn't plan on writing all this, but here it is anyway
* I'll let you figure out how you should determine what to pass in for the instance, I can tell you that an instance of the parent type won't work here, you will probably have to modify GetCustomAttributes to return a hierarchial collection instead of a flat one
James
"It is self repeating, of unknown pattern"
Data - Star Trek: The Next Generation
|
|
|
|
|

|
Patrick Foo wrote:
How do we change the attributes during runtime?
You really can't, Attributes are used to describe meta-data which is embedded in the assembly at compile time. Because it is embedded at compile-time attributes are essentially constants, until the time (if ever) that .NET allows user-attributes to inject code into the assmblies the attributes are used on.
Patrick Foo wrote:
I got a property with an 'ReadOnly' attribte.
Right now, this property is displayed onto the PropertyGrid Control
in a window form.
Its a lot more involved than you are currently doing, but you can use PropertyDescriptor's (and its IsReadOnly property) to achieve what you want to do. However I'm not familiar at all with how you need to go about doing this, but I think there is a CodeProject article which describes it. Here it is: Bending the .NET PropertyGrid to Your Will[^].
Hope that helps,
James
"It is self repeating, of unknown pattern"
Data - Star Trek: The Next Generation
|
|
|
|

|
Hi,
I've been trying to work out a way of implementing the equivalent of C++ templates to define standard datatypes in VB.Net.
I have a situation where I want to create strongly typed ArrayLists for about 10 different class of objects, and the suggested method is to either wrap or subclass the ArrayList class, but this seems to be an awful waste of coding simply to enforce a cast on the Object parameter of 10 methods and properties
Is there any way the Attributes could be used to override the datatype of parameters inside a class, or am I barking up the wrong tree?
Many thanks,
iGadget
p.s. Very good article, and one of the only ones on the web!
|
|
|
|

|
iGadget wrote:
Is there any way the Attributes could be used to override the datatype of parameters inside a class, or am I barking up the wrong tree?
At the moment you are looking at the wrong solution. In order for this to work well you would need the compiler to specifically look for your attributes so it can generate the proper code. So you're still looking at waiting for generics to be provided by .NET (possibly in version 2.0).
Meanwhile, I highly suggest using Chris Sells' CollectionGen[^] for creating any custom collections you need. It has support for a Vector (ArrayList substitute), Hashtable, and SortedList.
Even better is that the Vector doesn't use the ArrayList, so you don't incur boxing penalties for ValueTypes.
James
Sig code stolen from David Wulff
|
|
|
|

|
Hi all!
I've just started to develop in .NET and I have run into a problem I just don't know how to solve:
I use the Directory class to do various things, for instance Directive::Exists, and this works fine, but the compiler will not accept Directive::CreateDirective. The error message is: error C2039: 'CreateDirectoryA': is not a member of 'System::IO::Directory'.
At first I thought it had to do with the character set so I changed from Multi-Byte to Unicode but that did not help (the error message was then that "CreateDirectoryW" not was a member). My OS is Windows NT 4.0 sp6, but I have tried to compile my project on XP as well with the same result. Directory.CreateDirectory works fine in VB.
Another problem I have, that I think is related is that the compiler doesn't recognise MessageBox as a member of 'System::Windows::Forms'.
I'll be most grateful for any help!
EnkelIk
|
|
|
|

|
The problem you are seeing is that you have included some windows header files; which use #defines to make it so that you get the Ansi or Wide character versions of a function depending on whether UNICODE is defined.
To get around that problem, you need to undefine the macro somewhere in that source file before you use the CreateDirectory or MessageBox method/class.
#pragma push_macro("MessageBox")
#undef MessageBox
#pragma pop_macro("MessageBox")
HTH,
James
"And we are all men; apart from the females." - Colin Davies
|
|
|
|

|
I am writing a code generation tool that generates a new class based on existing classes. I use reflection to get the class members, and I want to copy all the existing attributes to the new class. However I can not get the attribute constructor information correct in the copied attributes. Any help or leads would be great.
|
|
|
|

|
I am interesting your programm which you mentioned above.
why no post it out?
My Homepage : http://www.accesine.com
|
|
|
|

|
Hi James,
I have a basic question abt custom attributes. Can
you pls spend some moment from precious time to get me
an idea abt custom attributes?
There is an attribute class X that can be applied at
class level. This attribute has been applied to a
class Y. When the class is instantiated, the attribute
applied to the class also created.
Now, my question is, why cant we directly create an
instance in your class Y? What is difference between
creating an instance of a class explicitly and
applying attribute over the class?
Or Is there anyother concept behind writing attribute
classes apart from this?
Actually, my requirement is...
whenever an exception occurs in my C# code, i want my
attribute class to handle that. I dont want to write
exception handlers in all my components.
In this scenario, where custom attributes come into
picture?
Pls explain.
Thanx in advance.
|
|
|
|

|
Hello James, very good article. Can you give any information on how a Custom Attribute could reflect on the class (item) it decorates? I am working on a Unit testing framework and I want to be able to store the test data AND generic test in a custom attribute class. Then, the testing application will ask the attribute to perform and report all tests. Reflection is needed so the custom attribute can decide if every property/method has a corresponding test and every test has a property/method. Also, reflection will alow the test to cascade down the class tree structue as the custom attribute will be able to construct custom attributes on all members.
Thanks, John
|
|
|
|

|
John Eliason wrote:
Hello James, very good article.
Thanks
John Eliason wrote:
Can you give any information on how a Custom Attribute could reflect on the class (item) it decorates?
You can create a static method on the attribute and have the coder call that method explicitly to do the work it needs to do
[MyAttribute()]
public string TestString {
get {
MyAttribute.DoWork();
return testString;
}
}
In MyAttribute.DoWork you would walk the stack to get to the instance that called the method. Ed Stegman posted code to do this for a custom attribute he wrote to make fixed length strings; however I can't find it in the DOTNET archives.
I'm not familiar with Unit Testing so you'll have to forgive any ignorance, but the same technique my article uses could still apply. In other words, at runtime you do a GetCustomAttributes on the MemberInfo type you are looking for (Type, FieldInfo, PropertyInfo, MethodInfo, etc). Then you do the same where else it is needed.
One thing that looks interesting is John Lam's Runtime Aspect Weaver. It will allow you to "weave" code in and out at runtime so you could put in some blanket code, "every time I call DoWork() I want it to call System.Diagnostics.Trace.Write("Output", theValue);".
Hope that gives you some ideas,
James
Sonork ID: 100.11138 - Hasaki
"Smile your little smile, take some tea with me awhile.
And every day we'll turn another page.
Behind our glass we'll sit and look at our ever-open book,
One brown mouse sitting in a cage."
"One Brown Mouse" from Heavy Horses, Jethro Tull 1978
|
|
|
|

|
Hi James,
Your article "Creating and Using Attributes in your .NET application"
is a great article, very interesting and helpfully.
Now I had modified your program.
// The classes:
[Serializable()]
public class TestClassA
{
public TestClassA() { }
}
[Test(4, Name = "TestClassB")]
public class TestClassB
{
public TestClassB() { }
}
// The print method:
public static void PrintTestAttributes(object obj)
{
Type type = obj.GetType();
SerializableAttribute [] sa =
(SerializableAttribute []) type.GetCustomAttributes(typeof(SerializableAttribute), false);
TestAttribute [] AttributeArray =
(TestAttribute []) type.GetCustomAttributes(typeof(TestAttribute), false);
...
}
Now I have the problem, that
GetCustomAttributes(typeof(SerializableAttribute), false);
allways return Length==0.
I have the same problem with MarshalAsAttribute.
I need to get the information SizeConst from a field.
// The class
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class UserInfo
{
public uint nUserNr;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=50)]
public string strUserName;
...
}
// the code
MarshalAsAttribute[] ma =
(MarshalAsAttribute[]) type.GetCustomAttributes(typeof(MarshalAsAttribute),
false);
ma.Length is always 0!
Do you have an idee how I can solve this problem?
Stefan
|
|
|
|
|
|

|
Dear James,
I am currently writing a Custom Attribute which can be used to serialize a class to Xml. The CA can be attached to the class and the properties inside the class. It looks something like this
<AttributeUsage (AttributeTargets.Class Or AttributeTargets.Property)> Public Class XmlModifier
Inherits System.Attribute
Private m_tXmlNode As System.Type ' defines the node type (XmlElement, XmlAttribute)
Private m_strNodeName As String ' xpath to the parent node
Private m_strParentXPath As String ' name of this node
<p>
[...] ' following New and readonly-properties for the members above
End Class
I then use the CA:
<XmlModifier(GetType(XmlElement), "", "root")> Class A
[...]
<XmlModifier(GetType(XmlElement), "/root", "Element1")> Public Property Element1()
[...]
<XmlModifier(GetType(XmlAttribute), "/root/Element1", "AnAttribute")> Public Property AnAttribute()
[...]
What I want to do, is to call a function, such as DynCreateXml(), which parses the properties and builds up an Xml Document:
<root>
<Element1 AnAttribute="123"/>
</root>
But I want to retrieve all CA's of a class in one single step. I found that GetCustomAttributes() needs detailed type information. But I don't see the sense to get CA's of a type I already know. Or am I wrong?
The other thing is, that I don't understand how to retrieve CA's assigned to a property.
Can you help me out?
Kind regards,
Michael
|
|
|
|

|
Michael Groeger wrote:
But I want to retrieve all CA's of a class in one single step.
There are two overloaded versions of GetCustomAttributes(), one that takes a type and a bool the other takes just the bool.
If you want to retreive all CA's attached to a class call it like this myType.GetCustomAttributes(bSearchClassHierarchy).
Michael Groeger wrote:
But I don't see the sense to get CA's of a type I already know.
Its really just a matter of efficiency. If you are only looking for a specific CA then passing in the CA's type makes sense; but if you are going to look for more than one CA it might be smarter to get all CA's then handle just the ones you want.
In order for a CA to be useful some code *somewhere* has to be written to do something with it specifically. This can happen at the compiler level (SerializableAttribute), at the framework level (MarshalAs), or in your own code (XmlModifier).
Michael Groeger wrote:
I don't understand how to retrieve CA's assigned to a property.
My VB is a bit rusty but I think this snippet will do it.
Public Sub PrintPropertyAttributes(Object o, Boolean bSearchClassHierarchy)
Dim Properties() as System.Reflection.PropertyInfo
Dim [Property] as System.Reflection.PropertyInfo
Dim Attributes() as Attribute
dim [Attribute] as Attribute
Dim [Type] as Type
[Type] = o.GetType()
Properties = [Type].GetProperties()
For Each [Property] in Properties
Attributes = [Property].GetCustomAttributes(bSearchClassHierarchy)
System.Console.WriteLine([Property].Name)
For Each [Attribute] in Attributes
System.Console.WriteLine(vbTab + [Attribute].ToString())
End For
End ForNow for another topic completely.
Did you know that MS already did most of what you're trying to do for you?
Check out the XmlSerializer in the System.Xml.Serialization namespace.
HTH,
James
Sonork ID: 100.11138 - Hasaki
"Smile your little smile, take some tea with me awhile.
And every day we'll turn another page.
Behind our glass we'll sit and look at our ever-open book,
One brown mouse sitting in a cage."
"One Brown Mouse" from Heavy Horses, Jethro Tull 1978
|
|
|
|

|
James T. Johnson wrote:
Michael Groeger wrote:
But I want to retrieve all CA's of a class in one single step.
There are two overloaded versions of GetCustomAttributes(), one that takes a type and a bool the other takes just the bool.
If you want to retreive all CA's attached to a class call it like this myType.GetCustomAttributes(bSearchClassHierarchy).
Oh I see. Okay, this will help me out.
James T. Johnson wrote:
Michael Groeger wrote:
But I don't see the sense to get CA's of a type I already know.
Its really just a matter of efficiency. If you are only looking for a specific CA then passing in the CA's type makes sense; but if you are going to look for more than one CA it might be smarter to get all CA's then handle just the ones you want.
Ok. Of course you're right. My point of view to attributes might have been delimited to my current situation, which afforded to get all attributes attached to a class.
James T. Johnson wrote:
Michael Groeger wrote:
I don't understand how to retrieve CA's assigned to a property.
My VB is a bit rusty but I think this snippet will do it.
Thankyou for the example. As the class library is for all the same, I think you've also could have written some pseudo-code, which just uses the correct libs For instance, I would have no problem if you are writing c# as I am normally a c++ developer and only the current project affords using vb.
James T. Johnson wrote:
Now for another topic completely.
Did you know that MS already did most of what you're trying to do for you?
Check out the XmlSerializer in the System.Xml.Serialization namespace.
Hehe. I tried this already and it looks quite good. But what I don't like is that you have to build your classes the way the Xml should look alike. So I think, I will try to expand the XmlSerializer to match my issues.
Kind regards,
Michael
|
|
|
|

|
Hi there, I understand that Microsoft has openeed up everything they have to offer in terms of classes, reflection, emit etc and exposed all the programming blocks. Similarly they have opened the Attributes also. I understand that, with Attribute class, you can keep creating, deleting attributes on the fly. That is where a technical feasibility is attained. Buy, what I'm interested is that, why they have given so many attibutes and extending the attributes, what benefits you are going to get. What are the practical kind of application are we looking at to apply these dynamic attributes? Thanks in advance for such a article.
|
|
|
|

|
Anonymous wrote:
I understand that, with Attribute class, you can keep creating, deleting attributes on the fly.
Much of what I have seen that does that is in the Xml.Serialization namespace of classes. If you want you can override some of the serializers settings so that data is handled differently. But I wouldn't call this a dynamic application of attributes since the XmlSerializer looks for the XmlAttributeOverrides property specifically, rather than a class having an attribute at one point and not having it at another point during execution.
Anonymous wrote:
extending the attributes, what benefits you are going to get.
By creating your own attributes you are really just letting yourself re-use existing code.
In one of my projects I created a set of attributes and classes that serialized a class to a database, where every field and property could correspond to a field in the database. The attributes specified the Field name, its datatype and length, whether it was nullable or a primary key, and where it should be added as a parameter to the DbCommand object.
My DbSerializer class would then build a list of these attributes and when calling its serialize function it would fetch the values, then add them to the command object.
I wrote this because everytime I was writing a class that represented an object in the database I was writing pretty much the same code everytime for saving/loading to/from the database.
Many of the attributes in the CLR are just there so that you can use code over again. The MarshalAs attribute tells the PInvoke functions how to change the layout of your data so that you don't have to everytime you use PInvoke. The Serializable attribute sets a bit in the metadata for your class that tells the runtime your class is serializable.
Some of the attributes tell the compiler how to handle something, such as the Serializable attribute, many of the Assembly and module attributes do the same.
In Visual Studio Magazine there is an article that shows how you can use attributes to create a Windows Form that will modify its conents based on the class passed in.
I hope that made some sense,
James
Sonork ID: 100.11138 - Hasaki
"Smile your little smile, take some tea with me awhile.
And every day we'll turn another page.
Behind our glass we'll sit and look at our ever-open book,
One brown mouse sitting in a cage."
"One Brown Mouse" from Heavy Horses, Jethro Tull 1978
|
|
|
|

|
Very nice answer and specific application. Would be
very interested in seeing the class which processes
the attributes
|
|
|
|
|

|
Senkwe Chanda wrote:
Question one...Why [Test(3)]? Isn't Test the name of the namespace? I'm not clear on that.
Test is the name of the namespace (and I probably should've chosen a better name), but because we're applying the attribute the framework will automatically add Attribute to the name for us. So [Test(3)] is really [TestAttribute(3)].
Senkwe Chanda wrote:
Question Two...I assume [Test(4, Name = "TestClassB")] initializes the Attribute. Suppose the attribute had two ints instead of an int and string as properties/public fields. What would that piece of code look like?
That depends on what constructors were available on the TestAttribute class. If you have a constructor that takes the two ints, then you should use that.
If you don't have a constructor available then you set each field/property at the end of the constructor but still inside the ). [Test(3, MySecondInt = 5, MyDouble = 3.05634)].
At first it seems really odd to set properties and fields inside of the constructor, especially when the only constructor defined takes a single integer as its only parameter. But after working with it for a little bit it seems almost second nature now.
HTH,
James
Sonork ID: 100.11138 - Hasaki
"My words but a whisper -- your deafness a SHOUT.
I may make you feel but I can't make you think." - Thick as a Brick, Jethro Tull 1972
|
|
|
|

|
Hi James,
Great article!!
I was doing some test but faced a problem that I can't solve...
Suppose I have a Custom attribute class named MyAttribute that is in the assembly MyAttribute.dll
Now I want to develop a new Assembly which uses the MyAttribute like this:
namespace XXX
{
[MyAttribute()]
public class Foo
{
...
}
}
But when I try to compile it using the csc it gives me following error:
Foo.cs(6,3): error CS0592: Attribute 'MyAttribute' is not valid on this declaration type. It is valid on '' declarations only.
To compile it:
csc /t:library /r:MyAttribute.dll /out:Foo.dll foo.cs
If I include the MyAttribute class in the Foo.dll it works. The problem seems to be the attribute class living in another assembly.
Thanks anyway,
- xico -
|
|
|
|

|
Forget about it,
The AttributeUsage was missing in my Attribute class.
Cheers,
- xico -
|
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
Shows how to use existing attributes and how to create and use your own attributes
| Type | Article |
| Licence | BSD |
| First Posted | 9 Feb 2002 |
| Views | 364,540 |
| Downloads | 3,441 |
| Bookmarked | 166 times |
|
|