1

I've recently been trying to make use of property attributes. The following code (in a different assembly) retrieves only those properties which have a specific attribute, by name. The problem is it requires that the searched for attribute be the first attribute. The code would break if a different attribute is added to the property, unless it is placed after the attribute being searched for.

IList<PropertyInfo> listKeyProps = properties
    .Where(p => p.GetCustomAttributes(true).Length > 0)
    .Where(p => ((Attribute)p.GetCustomAttributes(true)[0])
        .GetType().Name == "SomeAttribute")
    .Select(p => p).ToList();

I did look at this answer, but couldn't make it work since the objects are in Assembly.GetEntryAssembly() and I can't directly call typeof(SomeAttribute).

How can this be changed so as to be less fragile?

[Edit:] I found a way to determine the attribute type, despite it being in a different assembly.

Assembly entryAssembly = Assembly.GetEntryAssembly();
Type[] types = entryAssembly.GetTypes();
string assemblyName = entryAssembly.GetName().Name;
string typeName = "SomeAttribute";
string typeNamespace
    = (from t in types
       where t.Name == typeName
       select t.Namespace).First();
string fullName = typeNamespace + "." + typeName + ", " + assemblyName;
Type attributeType = Type.GetType(fullName);

Then I was able to use IsDefined(), as proposed below by dcastro:

IList<PropertyInfo> listKeyProps = properties
    .Where(p => p.IsDefined(attributeType, true)).ToList();
Community
  • 1
  • 1

1 Answers1

2

So, you're trying to filter a list of properties, and retrieve only those who declare a specific attribute? If you know the attribute's type at compile time, you can replace that whole block with this:

Type attrType = typeof (SerializableAttribute);
properties.Where(p => p.IsDefined(attrType));

If you really need to identify the attribute's type by name, then use this instead:

properties.Where(p => p.CustomAttributes.Any(
    attr => attr.AttributeType.Name == "SomeAttribute"));

Edit

Replying to the second part of your question: you are overcomplicating things. In order to get the Type object from an assembly, all you need is this:

var attributeType = entryAssembly.GetTypes()
                                    .FirstOrDefault(t => t.Name == "SomeAttribute");

if (attributeType != null)
{
    //the assembly contains the type
}
else
{
    //type was not found
}

You don't have to (read: should not) retrieve the assembly name, type name, namespace and then concatenate everything.

But is there any point in retrieving the Type object? You're still using a string to retrieve a type, which is hard to maintain and easy to break. Have you thought of other possibilities?

If you have any more questions, please post them as a separate question.

dcastro
  • 66,540
  • 21
  • 145
  • 155
  • thank you very much for pointing me in the right direction. The code I added will do the job, yes? – Al Harrison Nov 08 '13 at 00:22
  • I'm looking at different ways to flag properties derived from primary keys when generating DTO classes, to be used later by a DAL at runtime in a 'where' clause (micro-Orm stuff, a hobby project). An attribute named "PrimaryKey" seemed like a better approach than what I had done before. New to Linq, you've helped me immensely, thank you. – Al Harrison Nov 08 '13 at 02:25