Reputation: 85
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
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