Code to get all properties supporting an attribute

J

jehugaleahsa

Hello:

I would like code that will return all properties that have a
specified attribute type.

And, once that is done, I would like code that returned all properties
that have an attribute that had a property value equal to a given
value. :)

In my case, I have a bunch of attributes associated with properties in
my business objects that specify the database column name that the
property works with. I would like to implement INotifyPropertyChanged
generically in an abstract base class called ABusinessObject.
ABusinessObject is responsible for taking the database column name and
updating a data store. When it does, I would like it to raise the
PropertyChanged event. However, PropertyChanged event is expected to
return the property name, not the column name.

Now, since my attributes hold the database column names for the
associated property, I should be able to look at my
"ABusinessObject.GetType().GetProperties()
[0..*].Attributes[0..*].ColumnName" and property with an attribute
with the column name I am given.

Pretty crazy, huh?

Anyway, below is the gross code (it has a goto in it) for finding what
I am looking for. I was hoping someone knew a better way.

if (propertyChanged != null)
{
Type businessObjectType = this.GetType();
string propertyName = columnName; // use as a default
foreach (PropertyInfo property in
businessObjectType.GetProperties())
{
foreach (ColumnInformationAttribute attribute
in
property.GetCustomAttributes(typeof(ColumnInformationAttribute),
true))
{
if (attribute.Name == columnName)
{
propertyName = property.Name;
goto found;
}
}
}
found:
propertyChanged(this, new
PropertyChangedEventArgs(propertyName));
}

Thanks,
Travis
 
J

Jeroen Mostert

I would like code that will return all properties that have a
specified attribute type.

And, once that is done, I would like code that returned all properties
that have an attribute that had a property value equal to a given
value. :)

In my case, I have a bunch of attributes associated with properties in
my business objects that specify the database column name that the
property works with. I would like to implement INotifyPropertyChanged
generically in an abstract base class called ABusinessObject.
ABusinessObject is responsible for taking the database column name and
updating a data store. When it does, I would like it to raise the
PropertyChanged event. However, PropertyChanged event is expected to
return the property name, not the column name.
Then make sure that either ABusinessObject has the property name too, or the
child classes are kind enough to implement this functionality by
implementing an abstract protected method that ABusinessObject can call.

Am I being too obvious here? What you want is of course possible, but it's a
pointless headache. You're giving a class a responsibility it can't fulfil
unless it grovels around in data that doesn't belong to it, which is usually
a sign you're putting the responsibility where you want to see it instead of
where it belongs.

Iterating over metadata *every single time a property is updated* is just
wasteful. Of course you could optimize it by iterating just once... but then
you'd have to cache the results, so you're back to my "make sure
ABusinessObject has the property names" recommendation.
 
J

jehugaleahsa

Then make sure that either ABusinessObject has the property name too, or the
child classes are kind enough to implement this functionality by
implementing an abstract protected method that ABusinessObject can call.

My business objects are kind enough to provide the attribute. The
point of ABusinessObject is to provide a generic solution for all
business objects. Of course it would be more efficient if every
property handled the NotifyPropertyChanged event themselves, but then
I have peers who would screw up more than often. The abstract
protected method is a good idea, but it would cause the same
suffering, since you would have to convert column names to property
names, anyway. It gives me the benefit of a speed boost and the
guaruntee of existence. But, it also forces all my business objects to
implement the abstract method . . . I hate to put that responsibility
on my peers; they are much more comfortable with a simple attribute.
Am I being too obvious here? What you want is of course possible, but it's a
pointless headache. You're giving a class a responsibility it can't fulfil
unless it grovels around in data that doesn't belong to it, which is usually
a sign you're putting the responsibility where you want to see it instead of
where it belongs.

How can an abstract class that is part of a library possibly predict
what users of that library can and will do? I simply provide the
functionality *if* they provide the attribute. It is like a membership
card, or something. Fortunately, I have a custom code generator
provided with my library that will generate most of my business
objects for me (attributes included). I feel the same way, though; I
feel like my code is reaching out, trying to find its way in a dark
room. However, I use reflection extensively in my library to provide
features that would otherwise be impossible or require complex
generics. My main concern is keeping my peers using my library.

We recently tried to use my library in Windows Forms and there were
certain limitations that meant using my code was "harder". I want to
provide a certain level of automation to prevent regular, common
mistakes (which are extremely common in my case). So, I am trying to
extend my library to support validation, error reporting and property-
changed events. Its the property-changed events that are causing all
the problems. If I didn't already have a heirarchy tested and proved,
it wouldn't be too much to ask my peers to write their business
objects with all the bells and whistles. I mean, you could avoid the
whole issue involving getting a property with a column name. But then
I have to trust my peers to be consistent, which is hard enough for me
to do. But how much do I want to depend on meta data, for the same
reason?
Iterating over metadata *every single time a property is updated* is just
wasteful. Of course you could optimize it by iterating just once... but then
you'd have to cache the results, so you're back to my "make sure
ABusinessObject has the property names" recommendation.

My thought was that NotifyPropertyChanged events are interface driven,
anyway. Interface equals little need for speed. However, I think I
might try caching the results, since they won't change. There is
always going to be the problem when an extensive amount of work is
done a business object behind the scenes before the interface regains
control. I don't know, I still feel like I am stretching.

Thanks for the insight,
Travis
 
M

Marc Gravell

Actually, if you use component-model (rather than reflection), then
TypeDescriptor.GetProperties() does something quite close - but under
the bonnet it will do something quite similar so I'm not sure I'd
bother with the complexity (and there are some issues if an
ICustomTypeDescriptor or TypeDescriptionProvider fails to correctly
support this usage).

So I'd probably use something akin to what you have, but a few
thoughts:
* You wany to be very cautious about raising PropertyChanged citing a
name that doesn't exist as a property; this can break several UI
implementations. In the "not found" case, you can normally use (null
or blank, I can't remember which) which kinda means "the whole
object".

* You can use break to get rid of your goto and improve readability.

* Regulars will think I'm a stuck record, but I'd be inclined to use
ComponentModel here - i.e. TypeDescriptor.GetProperties(type), not
type.GetProperties(); the difference is a: that the first supports
more flexibile scenarios, but more importantly: that is what the UI
binding code is using! And it would be nice if the two agreed...
The best example of the difference is a DataView; type.GetProperties()
yields "AllowDelete", "Container", etc (the properties of DataView) -
where-as TypeDescriptor.GetProperties(type) will yield the columns in
the DataTable [note I'm not a big fan of DataTable, but it makes a
simple example of what I am talking about].

Marc
 
M

Marc Gravell

so I'm not sure I'd bother with the complexity
I mean tthe complexity of the overload that accepts an Attribute[] for
filtering; I would *absolutely* take the time to change to use
TypeDescriptor and PropertyDescriptor.

Marc
 
J

jehugaleahsa

so I'm not sure I'd bother with the complexity

I mean tthe complexity of the overload that accepts an Attribute[] for
filtering; I would *absolutely* take the time to change to use
TypeDescriptor and PropertyDescriptor.

Marc

You know what, I talked to my peers here and told them that searching
for an attribute was insanely slow and buggy. They have agreed to
structure their property mutators similar to the following:

if (value != <the current value> && isValid(value, <list of tests>))
{
set("<column name>", value);
notifyChange("<property name>");
}

It will be a lot faster and allow the them to decide whether or not a
property supports notification/validation/etc.

Thanks again for the insight. You were totally right about putting the
responsibility in the wrong place.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top