Hi,
I'm having a reflection brain fog here, perhaps someone can set me on the right
track.
I'd like to define a custom attribute to be used in a class hierarchy.
What I want to do is to have an attribute which can be applied to a class definition
of a class which inherits from a base, mustinherit class. I want to define methods
in the base class which will access the contents of the attribute as it is applied to
a particular derived class.
This was reasonably easy to do when dealing with an instance of the derived class.
But, I need to be able to have these methods in the base class be shared, so the
attribute can be accessed as defined on the derived class, rather than on an instance
of the class.
That is, for the instance method I define a derived class with my custom attribute
as, say:
<MyCustomAttribute("String1", "String2")_
Public MyDerivedClass
Inherits MyBaseClass
...
Then, in the base class, I defined a method like:
Public ReadOnly Property ValueFromMyAttribute() as string
Get
Dim classtype As Type = Me.GetType
Dim attr As EntityAttribute =
DirectCast(Attribute.GetCustomAttribute(classtype, _
GetType(MyCustomAttribute)), MyCustomAttribute)
If attr IsNot Nothing Then
Return attr.PropertyForString1
Else
Return classtype.Name
End If
End Get
End Property
This seemed to work.
But, the requirement now exists to access the attribute's properties from SHARED
methods, since the values may be needed even if no instance of the derived class
exists.
It seems like this ought to be possible, but how? If I make the property shared,
then obviously there is no instance for "Me" to refer to, so this generates a compile
error. How can I get the type of the derived CLASS instead of from an instance of
that class? I assume if I can get that, I can track down the attribute and access
its properties as I did above.
Thanks,
-- Jeff 15 2106
Hi Jeff,
if the problem were just to obtain the type you could use
GetType(YourBaseClass) ...
but I am a little perplexed as it does not seem to make sense to have
attributes
detached from an instance.
Can you make an example where this can be meaningful. And why you need
to
use attributes to do that ?
-tom
Jeff Mason ha scritto:
Hi,
I'm having a reflection brain fog here, perhaps someone can set me on the right
track.
I'd like to define a custom attribute to be used in a class hierarchy.
What I want to do is to have an attribute which can be applied to a class definition
of a class which inherits from a base, mustinherit class. I want to define methods
in the base class which will access the contents of the attribute as it is applied to
a particular derived class.
This was reasonably easy to do when dealing with an instance of the derived class.
But, I need to be able to have these methods in the base class be shared, so the
attribute can be accessed as defined on the derived class, rather than on an instance
of the class.
That is, for the instance method I define a derived class with my custom attribute
as, say:
<MyCustomAttribute("String1", "String2")_
Public MyDerivedClass
Inherits MyBaseClass
...
Then, in the base class, I defined a method like:
Public ReadOnly Property ValueFromMyAttribute() as string
Get
Dim classtype As Type = Me.GetType
Dim attr As EntityAttribute =
DirectCast(Attribute.GetCustomAttribute(classtype, _
GetType(MyCustomAttribute)), MyCustomAttribute)
If attr IsNot Nothing Then
Return attr.PropertyForString1
Else
Return classtype.Name
End If
End Get
End Property
This seemed to work.
But, the requirement now exists to access the attribute's properties from SHARED
methods, since the values may be needed even if no instance of the derived class
exists.
It seems like this ought to be possible, but how? If I make the property shared,
then obviously there is no instance for "Me" to refer to, so this generates a compile
error. How can I get the type of the derived CLASS instead of from an instance of
that class? I assume if I can get that, I can track down the attribute and access
its properties as I did above.
Thanks,
-- Jeff
On 31 Jul 2006 01:54:21 -0700, to**************@uniroma1.it wrote:
>Hi Jeff,
if the problem were just to obtain the type you could use GetType(YourBaseClass) ...
I think I tried GetType(YourBaseClass), but it returned the type of the Base class
instead of the derived class. The derived class is where the attribute is located.
>but I am a little perplexed as it does not seem to make sense to have attributes detached from an instance.
Can you make an example where this can be meaningful. And why you need to use attributes to do that ?
I was hoping to avoid the "why do you need to do that" sorts of questions, since they
can be distracting from the problem at hand, but OK.
The attribute I'd like to define is a "Friendly Name" attribute. This name will be
used in, for example, error messages involving the class. I may define a class
called, say, "EntLOB", but I want to use a more friendly name, like, "Enterprise Line
of Business" when presenting errors involving that class.
Many times the "Friendly Name" is the same as the class name (like "Customer"), but
in more than a few cases the class name I may use as a programmer is not the best
choice as a name for presentation to an end user.
It's true that almost all error messages would involve an instance of the class, but
consider the case where an instance of the object cannot be created at all. Perhaps
the user has entered some data (e.g. search criteria) which prevents an instance from
being created. The network could be down. The database could be offline. I'd like
the error message to be something like:
Unable to retrieve the Enterprise Line of Business because ...
rather than
Unable to retrieve the EntLOB because ...
The former is more, er, friendly, than the latter.
Since the database went offline, the object could not be constructed and there is no
instance of the EntLOB class available to get the type of. Since all the objects that
I may create derive from a common base class, I'd like to decorate my derived classes
with this attribute as appropriate, and have a common method, implemented in the base
class, which accesses this attribute and returns the specified name from the
attribute.
Since I may need to access this property even if no specific instance of the derived
class exists, I want to define a shared method in the base class which returns the
friendly name of the derived class (i.e. rather than the name of an instance), which
is where the attribute is located. I was hoping that I could use syntax like:
errormsg = string.format("Unable to retrieve {0} ...", EntLOB.FriendlyName, ...) ...
where FriendlyName is a shared readonly property implemented in the base class.
HTH,
-- Jeff
hi Jeff,
Couldn't you, in case of error, just create a "dummy" instance of the
derived class,
decorated as you wish?
In this case you could also change the attributes depending on the
exception type.
Do you think that could make sense?
-tom
Jeff Mason ha scritto:
On 31 Jul 2006 01:54:21 -0700, to**************@uniroma1.it wrote:
Hi Jeff,
if the problem were just to obtain the type you could use
GetType(YourBaseClass) ...
I think I tried GetType(YourBaseClass), but it returned the type of the Base class
instead of the derived class. The derived class is where the attribute is located.
but I am a little perplexed as it does not seem to make sense to have
attributes detached from an instance.
Can you make an example where this can be meaningful. And why you need
to use attributes to do that ?
I was hoping to avoid the "why do you need to do that" sorts of questions, since they
can be distracting from the problem at hand, but OK.
The attribute I'd like to define is a "Friendly Name" attribute. This name will be
used in, for example, error messages involving the class. I may define a class
called, say, "EntLOB", but I want to use a more friendly name, like, "Enterprise Line
of Business" when presenting errors involving that class.
Many times the "Friendly Name" is the same as the class name (like "Customer"), but
in more than a few cases the class name I may use as a programmer is not the best
choice as a name for presentation to an end user.
It's true that almost all error messages would involve an instance of the class, but
consider the case where an instance of the object cannot be created at all. Perhaps
the user has entered some data (e.g. search criteria) which prevents an instance from
being created. The network could be down. The database could be offline. I'd like
the error message to be something like:
Unable to retrieve the Enterprise Line of Business because ...
rather than
Unable to retrieve the EntLOB because ...
The former is more, er, friendly, than the latter.
Since the database went offline, the object could not be constructed and there is no
instance of the EntLOB class available to get the type of. Since all the objects that
I may create derive from a common base class, I'd like to decorate my derived classes
with this attribute as appropriate, and have a common method, implemented in the base
class, which accesses this attribute and returns the specified name from the
attribute.
Since I may need to access this property even if no specific instance of the derived
class exists, I want to define a shared method in the base class which returns the
friendly name of the derived class (i.e. rather than the name of an instance), which
is where the attribute is located. I was hoping that I could use syntax like:
errormsg = string.format("Unable to retrieve {0} ...", EntLOB.FriendlyName, ...) ...
where FriendlyName is a shared readonly property implemented in the base class.
HTH,
-- Jeff
On 31 Jul 2006 05:04:38 -0700, to**************@uniroma1.it wrote:
>hi Jeff,
Couldn't you, in case of error, just create a "dummy" instance of the derived class, decorated as you wish?
In this case you could also change the attributes depending on the exception type. Do you think that could make sense?
Hi Tom,
I suppose, but error exceptions may not be the only reason why the UI would want to
display the friendly name of a class without having an instance of the class. It
happens that a failure to retrieve was the immediate example I thought of in my
reply, but I can certainly think of other reasons (labels, captions, informational
messages, etc.)
(This is why I don't like answering the "why are you doing this" types of questions -
we can get afield of the orginal question :-)
Obviously, I can require that a derived class implement a specific (shared) friendly
name method which returns the derived class's friendly name via MustImplement
definitions in the base class.
But, I was hoping for a more "elegant" solution using a custom attribute. That way,
the developer of the derived class can supply the custom attribute only if the
friendly name is different than the class name, and all they have to do is provide
the attribute; the base class takes care of everything else.
This was easy to do when I had an instance of the derived class.
So I guess the question boils down to how do I get the Type of a derived class from
within a SHARED method in that derived class's base class (where there is no
instance)?
Is this even possible via reflection? (It feels like it ought to be, but what do I
know...)
-- Jeff
See if this get close to what you want (watch out line breaks, VB
2005):
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
'Instance version
Dim MyDerivedClass As New MyDerivedClass_Instance
With MyDerivedClass
MsgBox(.ValueFromMyAttribute(1))
MsgBox(.ValueFromMyAttribute(2))
End With
'Shared version
MsgBox(MyBaseClass.S_ValueFromMyAttribute(1))
MsgBox(MyBaseClass.S_ValueFromMyAttribute(2))
End Sub
Class MyCustomAttribute
Inherits Attribute
Public PropertyForString1 As String
Public PropertyForString2 As String
Sub New(ByVal s1 As String, ByVal s2 As String)
Me.PropertyForString1 = s1
Me.PropertyForString2 = s2
End Sub
End Class
<MyCustomAttribute("Default1", "Default2")_
Public Class MyDerivedClass
Inherits MyBaseClass
End Class
<MyCustomAttribute("Hi", "Jeff")_
Public Class MyDerivedClass_Instance
Inherits MyBaseClass
End Class
Class MyBaseClass
Public ReadOnly Property ValueFromMyAttribute(ByVal Index As
Integer) As String
Get
Dim classtype As Type = Me.GetType
Dim attr As MyCustomAttribute =
DirectCast(Attribute.GetCustomAttribute(classtype,
GetType(MyCustomAttribute)), MyCustomAttribute)
If attr IsNot Nothing Then
Select Case Index
Case 1
Return attr.PropertyForString1
Case 2
Return attr.PropertyForString2
Case Else
Return "unexpected arg"
End Select
Else
Return "no attribute"
End If
End Get
End Property
Public Shared ReadOnly Property S_ValueFromMyAttribute(ByVal
Index As Integer) As String
Get
Dim classtype As Type = GetType(MyDerivedClass)
Dim attr As MyCustomAttribute =
DirectCast(Attribute.GetCustomAttribute(classtype,
GetType(MyCustomAttribute)), MyCustomAttribute)
If attr IsNot Nothing Then
Select Case Index
Case 1
Return attr.PropertyForString1
Case 2
Return attr.PropertyForString2
Case Else
Return "unexpected arg"
End Select
Else
Return "no attribute"
End If
End Get
End Property
End Class
End Class
-tom
Datatime Community (free) http://cam70.sta.uniroma1.it/Community/
Jeff Mason ha scritto:
On 31 Jul 2006 05:04:38 -0700, to**************@uniroma1.it wrote:
hi Jeff,
Couldn't you, in case of error, just create a "dummy" instance of the
derived class, decorated as you wish?
In this case you could also change the attributes depending on the
exception type.
Do you think that could make sense?
Hi Tom,
I suppose, but error exceptions may not be the only reason why the UI would want to
display the friendly name of a class without having an instance of the class. It
happens that a failure to retrieve was the immediate example I thought of in my
reply, but I can certainly think of other reasons (labels, captions, informational
messages, etc.)
(This is why I don't like answering the "why are you doing this" types of questions -
we can get afield of the orginal question :-)
Obviously, I can require that a derived class implement a specific (shared) friendly
name method which returns the derived class's friendly name via MustImplement
definitions in the base class.
But, I was hoping for a more "elegant" solution using a custom attribute. That way,
the developer of the derived class can supply the custom attribute only if the
friendly name is different than the class name, and all they have to do is provide
the attribute; the base class takes care of everything else.
This was easy to do when I had an instance of the derived class.
So I guess the question boils down to how do I get the Type of a derived class from
within a SHARED method in that derived class's base class (where there is no
instance)?
Is this even possible via reflection? (It feels like it ought to be, but what do I
know...)
-- Jeff
On 31 Jul 2006 07:32:01 -0700, to**************@uniroma1.it wrote:
> See if this get close to what you want (watch out line breaks, VB 2005):
[snippage]
Dim MyDerivedClass As New MyDerivedClass_Instance
[snippage]
<MyCustomAttribute("Hi", "Jeff")_
Public Class MyDerivedClass_Instance
Inherits MyBaseClass
End Class
Class MyBaseClass
[snippage]
Public Shared ReadOnly Property S_ValueFromMyAttribute(ByVal Index As Integer) As String
Get
Dim classtype As Type = GetType(MyDerivedClass)
Dim attr As MyCustomAttribute = DirectCast(Attribute.GetCustomAttribute(classtype , GetType(MyCustomAttribute)), MyCustomAttribute)
If attr IsNot Nothing Then
Select Case Index
Case 1
Return attr.PropertyForString1
Case 2
Return attr.PropertyForString2
Case Else
Return "unexpected arg"
End Select
Else
Return "no attribute"
End If
End Get
End Property
End Class
End Class
Ah, but MyBaseClass is used as a base for many different classes, so referring to the
derived class via GetType(MyDerivedClass) won't do, since that "hardwires" a
particular derived class inside the base class. Any number of other classes would
also derive from the base, each with their own attribute.
As I think about it, there could even be an entire class hierarchy which derives from
the base class. It would be a reasonable restriction for the base to assume that the
attribute only appeared on the most derived class from the base.
-- Jeff
I anticipated your observation by 2 using 2 classes:
MyDerivedClass_Instance
MyDerivedClass
both display correct attributes, although the same type is used in the
gettype.
Can you make an example where this scheme would fail, so that we can
fix it ?
-tom
Jeff Mason ha scritto:
On 31 Jul 2006 07:32:01 -0700, to**************@uniroma1.it wrote:
See if this get close to what you want (watch out line breaks, VB
2005):
[snippage]
Dim MyDerivedClass As New MyDerivedClass_Instance
[snippage]
<MyCustomAttribute("Hi", "Jeff")_
Public Class MyDerivedClass_Instance
Inherits MyBaseClass
End Class
Class MyBaseClass
[snippage]
Public Shared ReadOnly Property S_ValueFromMyAttribute(ByVal
Index As Integer) As String
Get
Dim classtype As Type = GetType(MyDerivedClass)
Dim attr As MyCustomAttribute =
DirectCast(Attribute.GetCustomAttribute(classtype,
GetType(MyCustomAttribute)), MyCustomAttribute)
If attr IsNot Nothing Then
Select Case Index
Case 1
Return attr.PropertyForString1
Case 2
Return attr.PropertyForString2
Case Else
Return "unexpected arg"
End Select
Else
Return "no attribute"
End If
End Get
End Property
End Class
End Class
Ah, but MyBaseClass is used as a base for many different classes, so referring to the
derived class via GetType(MyDerivedClass) won't do, since that "hardwires" a
particular derived class inside the base class. Any number of other classes would
also derive from the base, each with their own attribute.
As I think about it, there could even be an entire class hierarchy which derives from
the base class. It would be a reasonable restriction for the base to assume that the
attribute only appeared on the most derived class from the base.
-- Jeff
On 31 Jul 2006 08:32:37 -0700, to**************@uniroma1.it wrote:
>I anticipated your observation by 2 using 2 classes:
MyDerivedClass_Instance MyDerivedClass
both display correct attributes, although the same type is used in the gettype. Can you make an example where this scheme would fail, so that we can fix it ?
I really appreciate your help and interest here.
Let's concentrate on the issue where no class instance is involved, and the shared
method on the base class is invoked through the derived class (since that's were my
problem lies).
Suppose I define two classes both decorated with their own version of the attribute:
<MyCustomAttribute("Default1", "Default2")_
Public Class MyDerivedClass
Inherits MyBaseClass
End Class
<MyCustomAttribute("Hi", "Tom")_
Public Class AnotherDerivedClass
Inherits MyBaseClass
End Class
How would the assignment of the 'classtype' variable in the base's shared method be
made? As you originally suggested, it was:
Dim classtype As Type = GetType(MyDerivedClass)
but now I have two classes, MyDerivedClass AND AnotherDerivedClass, both of which
derive from MyBaseClass, and for both of which I'd like to evaluate each's attribute,
as, say:
Dim x as string = MyDerivedClass.S_ValueFromMyAttribute(1)
Dim y as string = AnotherDerivedClass.S_ValueFromMyAttribute(1)
I would hope to return x = "Default1" and y = "Hi".
It seems to me that GetType won't work here as it needs an explicit Type as its
argument. Since there can be multiple classes that inherit from the base, I don't
know that Type in the base class, as it is only known at run-time when the shared
method is invoked.
I'm thinking that some other form of reflection is required to get the Type of the
derived classin the base's shared method. I have no idea what that might be...
-- Jeff
Ok let's make another attempt... :)
What do you think of this ? (at least the result is that wanted)
It only requires an additional statement in the derived class:
Imports System.Reflection
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
'Shared version
MsgBox(AnotherDerivedClass.ValueFromMyAttribute_St atic(1,
AnotherDerivedClass.WhoAmI))
MsgBox(AnotherDerivedClass.ValueFromMyAttribute_St atic(2,
AnotherDerivedClass.WhoAmI))
MsgBox(MyDerivedClass.ValueFromMyAttribute_Static( 1,
MyDerivedClass.WhoAmI))
MsgBox(MyDerivedClass.ValueFromMyAttribute_Static( 2,
MyDerivedClass.WhoAmI))
End Sub
Class MyCustomAttribute
Inherits Attribute
Public PropertyForString1 As String
Public PropertyForString2 As String
Sub New(ByVal s1 As String, ByVal s2 As String)
Me.PropertyForString1 = s1
Me.PropertyForString2 = s2
End Sub
End Class
<MyCustomAttribute("Default1", "Default2")_
Public Class MyDerivedClass
Inherits MyBaseClass
Public Shared WhoAmI As Type = GetType(MyDerivedClass)
End Class
<MyCustomAttribute("Hi", "Jeff")_
Public Class AnotherDerivedClass
Inherits MyBaseClass
Public Shared WhoAmI As Type = GetType(AnotherDerivedClass)
End Class
Class MyBaseClass
Public Shared ReadOnly Property
ValueFromMyAttribute_Static(ByVal Index As Integer, ByVal WhoAmI As
Type) As String
Get
Dim classtype As Type = WhoAmI
Dim attr As MyCustomAttribute =
DirectCast(Attribute.GetCustomAttribute(classtype,
GetType(MyCustomAttribute)), MyCustomAttribute)
If attr IsNot Nothing Then
Select Case Index
Case 1
Return attr.PropertyForString1
Case 2
Return attr.PropertyForString2
Case Else
Return "unexpected arg"
End Select
Else
Return "no attribute"
End If
End Get
End Property
End Class
-Tom
Jeff Mason ha scritto:
On 31 Jul 2006 08:32:37 -0700, to**************@uniroma1.it wrote:
I anticipated your observation by 2 using 2 classes:
MyDerivedClass_Instance
MyDerivedClass
both display correct attributes, although the same type is used in the
gettype.
Can you make an example where this scheme would fail, so that we can
fix it ?
I really appreciate your help and interest here.
Let's concentrate on the issue where no class instance is involved, and the shared
method on the base class is invoked through the derived class (since that's were my
problem lies).
Suppose I define two classes both decorated with their own version of the attribute:
<MyCustomAttribute("Default1", "Default2")_
Public Class MyDerivedClass
Inherits MyBaseClass
End Class
<MyCustomAttribute("Hi", "Tom")_
Public Class AnotherDerivedClass
Inherits MyBaseClass
End Class
How would the assignment of the 'classtype' variable in the base's shared method be
made? As you originally suggested, it was:
Dim classtype As Type = GetType(MyDerivedClass)
but now I have two classes, MyDerivedClass AND AnotherDerivedClass, both of which
derive from MyBaseClass, and for both of which I'd like to evaluate each's attribute,
as, say:
Dim x as string = MyDerivedClass.S_ValueFromMyAttribute(1)
Dim y as string = AnotherDerivedClass.S_ValueFromMyAttribute(1)
I would hope to return x = "Default1" and y = "Hi".
It seems to me that GetType won't work here as it needs an explicit Type as its
argument. Since there can be multiple classes that inherit from the base, I don't
know that Type in the base class, as it is only known at run-time when the shared
method is invoked.
I'm thinking that some other form of reflection is required to get the Type of the
derived classin the base's shared method. I have no idea what that might be...
-- Jeff
On 31 Jul 2006 10:19:57 -0700, to**************@uniroma1.it wrote:
>Ok let's make another attempt... :)
What do you think of this ? (at least the result is that wanted) It only requires an additional statement in the derived class:
Well, that does indeed give the result wanted.
Please don't take this the wrong way, because I really do appreciate your help, but
it does make me think that it's a bit of hackery. (which is not necessarily a
prejorative term :-)
I guess the problem that I have with it is that it requires the developer of the
derived class to deal with the friendly name issue on three separate fronts. He must
provide the attribute on the class definition. He must define a constant within a
class that is the type of the very class he is defining. He must provide this
constant in every call to the FriendlyName method.
As I alluded to in an earlier post, I have in fact dealt with this issue in the past
by defining a FriendlyName (shared) method in the derived class. The base class
defined a MustInherit FriendlyName method, and each derived class in turn implemented
the method and returned the appropriate string.
I noticed, however, that the majority of the classes we defined had their
FriendlyName the same as their class name (e.g.'Customer'), so this resulted in a lot
of superfluous methods. I then got this bright idea to use an attribute instead. The
idea is that the developer would include the attribute only if a friendly name was
different than the class name. It seems to me that it is much simpler to define the
attribute when needed, and then reference the shared method "through" the derived
class. If no attribute was present, then the FriendlyName method would simply return
the ClassName.
Unfortunately I'm unable to find the magic incantation using reflection to do this.
Clearly, the runtime is in fact aware that MyDerivedClass inherits from MyBaseClass.
This is because MyDerivedClass.FriendlyName in fact invokes the FriendlyName method
in MyBaseClass. I was hoping that given that, there was a way to reflect "back" from
the base class to the derived class that invoked the method in it, without having an
instance of the derived class available to get the derived type.
sigh.
-- Jeff
Yes Jeff, I know it's a little bit hackery :) But it gets the job done
in a way that is, somehow, general. If I find a more elegant way I will
tell you, but I doubt it can be done with "pure" reflection, which is
based on instances. Actually, I was trying to be of help in an attempt
to convince myself that attributes are really useful for something.
But, at the present, I can see ways to do the same things in a much
more clear and maintenable way and I am not really persuaded of the
real usefulness of this stuff. For instance, often, enumerations used
in conjuction with hashtables and classes of attributes can get the job
done in a much more clear and maintenable way. I hope in the future to
see some useful way to integrate this notion in my programs, but so
far, frankly speaking, I am unable to give to this attribute stuff an
overwhelming importance. If you see situations where attributes are
really a useful replacement of other technique I would be very
interested to know them :)
-Tom
Jeff Mason ha scritto:
On 31 Jul 2006 10:19:57 -0700, to**************@uniroma1.it wrote:
Ok let's make another attempt... :)
What do you think of this ? (at least the result is that wanted)
It only requires an additional statement in the derived class:
Well, that does indeed give the result wanted.
Please don't take this the wrong way, because I really do appreciate your help, but
it does make me think that it's a bit of hackery. (which is not necessarily a
prejorative term :-)
I guess the problem that I have with it is that it requires the developer of the
derived class to deal with the friendly name issue on three separate fronts. He must
provide the attribute on the class definition. He must define a constant within a
class that is the type of the very class he is defining. He must provide this
constant in every call to the FriendlyName method.
As I alluded to in an earlier post, I have in fact dealt with this issue in the past
by defining a FriendlyName (shared) method in the derived class. The base class
defined a MustInherit FriendlyName method, and each derived class in turn implemented
the method and returned the appropriate string.
I noticed, however, that the majority of the classes we defined had their
FriendlyName the same as their class name (e.g.'Customer'), so this resulted in a lot
of superfluous methods. I then got this bright idea to use an attribute instead. The
idea is that the developer would include the attribute only if a friendly name was
different than the class name. It seems to me that it is much simpler to define the
attribute when needed, and then reference the shared method "through" the derived
class. If no attribute was present, then the FriendlyName method would simply return
the ClassName.
Unfortunately I'm unable to find the magic incantation using reflection to do this.
Clearly, the runtime is in fact aware that MyDerivedClass inherits from MyBaseClass.
This is because MyDerivedClass.FriendlyName in fact invokes the FriendlyName method
in MyBaseClass. I was hoping that given that, there was a way to reflect "back" from
the base class to the derived class that invoked the method in it, without having an
instance of the derived class available to get the derived type.
sigh.
-- Jeff
On 31 Jul 2006 12:52:37 -0700, to**************@uniroma1.it wrote:
>Yes Jeff, I know it's a little bit hackery :) But it gets the job done in a way that is, somehow, general. If I find a more elegant way I will tell you, but I doubt it can be done with "pure" reflection, which is based on instances. Actually, I was trying to be of help in an attempt to convince myself that attributes are really useful for something. But, at the present, I can see ways to do the same things in a much more clear and maintenable way and I am not really persuaded of the real usefulness of this stuff. For instance, often, enumerations used in conjuction with hashtables and classes of attributes can get the job done in a much more clear and maintenable way. I hope in the future to see some useful way to integrate this notion in my programs, but so far, frankly speaking, I am unable to give to this attribute stuff an overwhelming importance. If you see situations where attributes are really a useful replacement of other technique I would be very interested to know them :)
-Tom
Tom,
We found the following class (watch wrapping) which uses attributes useful. We use
enumerations all over the place, and it is helpful sometimes to define a "friendly"
description associated with an enum value. Of course, the ToString method on an
enumeration value will give you the name as defined by the enumeration, but we've
found it helpful to be able to attach an alternate Friendly Name to some enumerations
(to load up a combo box, say).
This uses the DescriptionAttribute located in the System.ComponentModel namespace
(since that was handy), but the technique could be applied to a custom attribute if
you're so inclined.
Thanks for your help, and it looks like I'll be abandoning the idea of a custom
attribute because unfortunately my requirement is that instances may not exist.
-----
Imports System.Reflection
Imports System.ComponentModel
Public Class EnumHelper
'Given an enumeration value, return its description attribute of that value.
'e.g. given:
'
' Public Enum people
' <Description("Jeff Mason")Jeff
' <Description("Dirk Digler")Dirk
' <Description("John Smith")John
' <Description("Sam Spade")Sam
' End Enum
'
'then calling this:
'
' GetEnumDescription(people.Jeff)
'
'would return this:
'
' "Jeff Mason"
'
Public Shared Function GetEnumDescription(ByVal value As [Enum]) As String
Dim fi As FieldInfo = value.GetType().GetField(value.ToString)
Dim attribs() As DescriptionAttribute =
DirectCast(fi.GetCustomAttributes(GetType(Descript ionAttribute), False),
DescriptionAttribute())
If attribs.Length 0 Then
Return attribs(0).Description
Else
Return value.ToString
End If
End Function
'Given an enumeration and the description of one of the items in it,
'get the value of the corresponding enumeration item.
'
'Given the people enum as above, calling:
'
' GetEnumValue(GetType(people), "John Smith")
'
'would return:
'
' 2
'
'Note that this function is optimized for integer enums. Use GetEnumValueObj if
the
'enum is some other type.
Public Shared Function GetEnumValue(ByVal t As Type, ByVal description As String)
As Integer
For Each e As [Enum] In e.GetValues(t)
If GetEnumDescription(e) = description Then
'its this one, so get the value from it
Dim i As FieldInfo = e.GetType().GetField(e.ToString)
Return CInt(i.GetValue(e))
End If
Next
Return Nothing
End Function
Public Shared Function GetEnumValueObj(ByVal t As Type, ByVal description As
String) As Object
For Each e As [Enum] In e.GetValues(t)
If GetEnumDescription(e) = description Then
'its this one, so get the value from it
Dim i As FieldInfo = e.GetType().GetField(e.ToString)
Return i.GetValue(e)
End If
Next
Return Nothing
End Function
'Given an enumeration and a description, check if any items in the enumeration
'have that description.
'
'Given the people enum as above, calling:
'
' GetEnumValueExists(GetType(people), "John Smith")
'
'would return true
'
'On the other hand calling:
'
' GetEnumValueExists(GetType(people), "Bob Jones")
'
'would return false
'
Public Shared Function GetEnumValueExists(ByVal t As Type, ByVal description As
String) As Boolean
For Each e As [Enum] In e.GetValues(t)
If GetEnumDescription(e) = description Then
'there is a match
Return True
End If
Next
'there isn't
Return False
End Function
'Get an arraylist of descriptions from an enumeration.
'(useful for populating comboboxes, etc.)
Public Shared Function GetEnumDescriptionArrayList(ByVal t As Type) As ArrayList
Dim al As New ArrayList
For Each e As [Enum] In e.GetValues(t)
al.Add(GetEnumDescription(e))
Next
Return al
End Function
End Class
-- Jeff
Thank you Jeff for the remarkable example. You could actually
write an interesting article on that.
I am beginning to see some light after the "fog" :)
-tom
Jeff Mason ha scritto:
On 31 Jul 2006 12:52:37 -0700, to**************@uniroma1.it wrote:
Yes Jeff, I know it's a little bit hackery :) But it gets the job done
in a way that is, somehow, general. If I find a more elegant way I will
tell you, but I doubt it can be done with "pure" reflection, which is
based on instances. Actually, I was trying to be of help in an attempt
to convince myself that attributes are really useful for something.
But, at the present, I can see ways to do the same things in a much
more clear and maintenable way and I am not really persuaded of the
real usefulness of this stuff. For instance, often, enumerations used
in conjuction with hashtables and classes of attributes can get the job
done in a much more clear and maintenable way. I hope in the future to
see some useful way to integrate this notion in my programs, but so
far, frankly speaking, I am unable to give to this attribute stuff an
overwhelming importance. If you see situations where attributes are
really a useful replacement of other technique I would be very
interested to know them :)
-Tom
Tom,
We found the following class (watch wrapping) which uses attributes useful. We use
enumerations all over the place, and it is helpful sometimes to define a "friendly"
description associated with an enum value. Of course, the ToString method on an
enumeration value will give you the name as defined by the enumeration, but we've
found it helpful to be able to attach an alternate Friendly Name to some enumerations
(to load up a combo box, say).
This uses the DescriptionAttribute located in the System.ComponentModel namespace
(since that was handy), but the technique could be applied to a custom attribute if
you're so inclined.
Thanks for your help, and it looks like I'll be abandoning the idea of a custom
attribute because unfortunately my requirement is that instances may not exist.
-----
Imports System.Reflection
Imports System.ComponentModel
Public Class EnumHelper
'Given an enumeration value, return its description attribute of that value.
'e.g. given:
'
' Public Enum people
' <Description("Jeff Mason")Jeff
' <Description("Dirk Digler")Dirk
' <Description("John Smith")John
' <Description("Sam Spade")Sam
' End Enum
'
'then calling this:
'
' GetEnumDescription(people.Jeff)
'
'would return this:
'
' "Jeff Mason"
'
Public Shared Function GetEnumDescription(ByVal value As [Enum]) As String
Dim fi As FieldInfo = value.GetType().GetField(value.ToString)
Dim attribs() As DescriptionAttribute =
DirectCast(fi.GetCustomAttributes(GetType(Descript ionAttribute), False),
DescriptionAttribute())
If attribs.Length 0 Then
Return attribs(0).Description
Else
Return value.ToString
End If
End Function
'Given an enumeration and the description of one of the items in it,
'get the value of the corresponding enumeration item.
'
'Given the people enum as above, calling:
'
' GetEnumValue(GetType(people), "John Smith")
'
'would return:
'
' 2
'
'Note that this function is optimized for integer enums. Use GetEnumValueObj if
the
'enum is some other type.
Public Shared Function GetEnumValue(ByVal t As Type, ByVal description As String)
As Integer
For Each e As [Enum] In e.GetValues(t)
If GetEnumDescription(e) = description Then
'its this one, so get the value from it
Dim i As FieldInfo = e.GetType().GetField(e.ToString)
Return CInt(i.GetValue(e))
End If
Next
Return Nothing
End Function
Public Shared Function GetEnumValueObj(ByVal t As Type, ByVal description As
String) As Object
For Each e As [Enum] In e.GetValues(t)
If GetEnumDescription(e) = description Then
'its this one, so get the value from it
Dim i As FieldInfo = e.GetType().GetField(e.ToString)
Return i.GetValue(e)
End If
Next
Return Nothing
End Function
'Given an enumeration and a description, check if any items in the enumeration
'have that description.
'
'Given the people enum as above, calling:
'
' GetEnumValueExists(GetType(people), "John Smith")
'
'would return true
'
'On the other hand calling:
'
' GetEnumValueExists(GetType(people), "Bob Jones")
'
'would return false
'
Public Shared Function GetEnumValueExists(ByVal t As Type, ByVal description As
String) As Boolean
For Each e As [Enum] In e.GetValues(t)
If GetEnumDescription(e) = description Then
'there is a match
Return True
End If
Next
'there isn't
Return False
End Function
'Get an arraylist of descriptions from an enumeration.
'(useful for populating comboboxes, etc.)
Public Shared Function GetEnumDescriptionArrayList(ByVal t As Type) As ArrayList
Dim al As New ArrayList
For Each e As [Enum] In e.GetValues(t)
al.Add(GetEnumDescription(e))
Next
Return al
End Function
End Class
-- Jeff
Hi Tom,
I just wanted to followup on our conversation. I think I found an
acceptable (just barely) way of handling my problem with accessing the
FriendlyName attribute from a base class when no instance of the derived
class exists.
What I did was to expose two overloaded methods in the base class, one
shared and one not. Both of these are essentially the code I've posted
before. The instance version of the FriendlyName property takes no arguments
and obtains the Type of the derived class via Me.GetType. The magic of
polymorphism insures this refers to the derived class. The call for an
instance of a derived object, which most calls are, is:
dim name as string = MyDerivedClassInstance.FriendlyName()
The shared method requires the Type of the calling object as an argument, as
e.g.:
dim name as string = MyDerivedClass.FriendlyName(GetType(MyDerivedClass ))
Passing the Type of the "calling" class allows the shared method in the base
class to use relection to obtain the attribute if there is one and process it
accordingly.
I object only mildly to the ugliness of the GetType as an argument, and this
has the distinct advantage of actually working.
--Jeff
Very good, Jeff.
Probably there is no way to escape the need of passing info about
the type, because, as you rightly noted, reflection works with actual
instances (unless we are missing something). And your way is an elegant
way to do it.
Why, sometime, don't you organize this information on a web page. I
think it would
be of interest to many people. :)
-Tom
Jeff Mason (Nospam) ha scritto:
Hi Tom,
I just wanted to followup on our conversation. I think I found an
acceptable (just barely) way of handling my problem with accessing the
FriendlyName attribute from a base class when no instance of the derived
class exists.
What I did was to expose two overloaded methods in the base class, one
shared and one not. Both of these are essentially the code I've posted
before. The instance version of the FriendlyName property takes no arguments
and obtains the Type of the derived class via Me.GetType. The magic of
polymorphism insures this refers to the derived class. The call for an
instance of a derived object, which most calls are, is:
dim name as string = MyDerivedClassInstance.FriendlyName()
The shared method requires the Type of the calling object as an argument, as
e.g.:
dim name as string = MyDerivedClass.FriendlyName(GetType(MyDerivedClass ))
Passing the Type of the "calling" class allows the shared method in the base
class to use relection to obtain the attribute if there is one and process it
accordingly.
I object only mildly to the ugliness of the GetType as an argument, and this
has the distinct advantage of actually working.
--Jeff
This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Edward Diener |
last post by:
If I set an attribute on some part of a class, such as a property or event,
does that attribute also apply to the same property or event of a derived
class ?
If the above is true, can I change...
|
by: John Brock |
last post by:
I have a base class with several derived classes (I'm writing in
VB.NET). I want each derived class to have a unique class ID (a
String), and I want the derived classes to inherit from the base...
|
by: Mark R. Dawson |
last post by:
Hi all,
I am trying to get custom attributes from a property. I can do this if I
pass in the name of the property i.e. "Name" to the reflection methods, but
if I pass in set_Name which is what...
|
by: prabhupr |
last post by:
Hi Folks
I was reading this article
(http://www.dotnetbips.com/articles/displayarticle.aspx?id=32) on
"Custom Attribute", written by Bipin.
The only thing I did not understand in this article...
|
by: =?Utf-8?B?cGFnYXRlcw==?= |
last post by:
Hello All,
I am sure that I am just overlooking something, but here's something I can't
quite get right...
I want to be able to get the value of a parameter of an unknown custom
attribute at...
|
by: hardieca |
last post by:
Hi!
I decorate my unfinished classes and methods with a custom TODO
attribute (as in things To Do). Using reflection, I am then able to
parse through my classes and output all TODOs to a list I...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM).
In this month's session, we are pleased to welcome back...
|
by: Vimpel783 |
last post by:
Hello!
Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
|
by: jfyes |
last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
|
by: ArrayDB |
last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
|
by: CloudSolutions |
last post by:
Introduction:
For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
|
by: Defcon1945 |
last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
|
by: Shællîpôpï 09 |
last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
|
by: Faith0G |
last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome former...
| | |