Al Harrison
Al Harrison

Reputation: 85

Retrieve properties with given attribute from different assembly

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();

Upvotes: 1

Views: 263

Answers (1)

dcastro
dcastro

Reputation: 68670

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.

Upvotes: 2

Related Questions