By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,771 Members | 1,862 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,771 IT Pros & Developers. It's quick & easy.

Custom Attributes, Shared methods, Derived classes and reflection

P: n/a
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
Jul 30 '06 #1
Share this Question
Share on Google+
15 Replies


P: n/a
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
Jul 31 '06 #2

P: n/a
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
Jul 31 '06 #3

P: n/a
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
Jul 31 '06 #4

P: n/a
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
Jul 31 '06 #5

P: n/a

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
Jul 31 '06 #6

P: n/a
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
Jul 31 '06 #7

P: n/a
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
Jul 31 '06 #8

P: n/a
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
Jul 31 '06 #9

P: n/a
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
Jul 31 '06 #10

P: n/a
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
Jul 31 '06 #11

P: n/a
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
Jul 31 '06 #12

P: n/a
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
Jul 31 '06 #13

P: n/a
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
Jul 31 '06 #14

P: n/a
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

Aug 1 '06 #15

P: n/a
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
Aug 1 '06 #16

This discussion thread is closed

Replies have been disabled for this discussion.