crissilvaeng
crissilvaeng

Reputation: 165

How to search a class within a namespace by the value of an attribute and return an object?

I need to make a factory of various objects. To be as abstract as possible. Able to create various objects, from a past condition by parameter, but without knewest concrete classes.

I want to do this by passing a value of an enum into a factory and it must be able, through reflection, to look for all classes within a namespace, which use the attribute whose value is the same as the last parameter.

I'm leaving the following code snippets to be used as reference.

An example of concrete class:

[Batatinha(SaborCode.Churrasco)]
internal class BatatinhaChurrasco : AbstractBatatinha
{
    public override string Sabor
    {
        get { return "Churrasco"; }
    }
}

An example of this factory:

internal class BatatinhaFactory
{
    internal AbstractBatatinha GetBatatinha(SaborCode sabor)
    {
        // Some logic ... possibly using reflection.
    }
}

An example of the desired call:

AbstractBatatinha batatinha = new BatatinhaFactory().GetBatatinha(SaborCode.Churrasco);
Console.WriteLine(batatinha.Sabor);
// ==> "Churrasco"

Obs.: The library should be portable. (.NET Framework 4.0.3, Silverlight 5, Windows 8, Windows Phone 8.1, Windows Phone Silverlight 8)

In Short: Given the value of an enum, how to retrieve the type of class that uses the parameter as an attribute using reflection?

Upvotes: 1

Views: 252

Answers (2)

Scott Hannen
Scott Hannen

Reputation: 29222

I think I understand what you're trying to do. I wrote my own classes and tested this:

public enum AttributeTypes
{
    TypeA, TypeB
}

public class ReferencesEnumAttribute : Attribute
{
    public AttributeTypes AttributeType { get; set; }

    public ReferencesEnumAttribute(AttributeTypes attributeType)
    {
        AttributeType = attributeType;
    }
}

public class FindsClassesByAttributeAndEnumValue
{
    public Type[] FindClassesInAssemblyContaining<T>(AttributeTypes attributeType)
    {
        return typeof (T).Assembly.GetTypes()
            .Where(type => type.GetCustomAttributes(false)
                .Any(attribute => attribute is ReferencesEnumAttribute
                  && ((ReferencesEnumAttribute) attribute).AttributeType == attributeType))
            .ToArray();

    }
}

Then a few classes with attributes:

[ReferencesEnum(AttributeTypes.TypeA)]
public class HasAttribute {}

[ReferencesEnum(AttributeTypes.TypeA)]
public class AlsoHasAttribute{}

[ReferencesEnum(AttributeTypes.TypeB)]
public class DoesntHaveAttribute {}

And finally a unit test:

[TestMethod]
public void GetClassesWithAttribute()
{
    var finder = new FindsClassesByAttributeAndEnumValue();
    var types = finder.FindClassesInAssemblyContaining<ReferencesEnumAttribute>(AttributeTypes.TypeA);
    Assert.AreEqual(2, types.Length);
}

You could also go a step further and put a constraint on it so that you only return types that inherit from a type or implement an interface. Otherwise you could get back types that have nothing in common except the attribute.

public class FindsClassesByAttributeAndEnumValue
{
    public Type[] FindClassesInAssemblyContaining<TContains,TInheritsFrom>(AttributeTypes attributeType)
        where TInheritsFrom : class
    {
        return typeof (TContains).Assembly.GetTypes()
            .Where(type => 
                type.IsAssignableFrom(typeof(TInheritsFrom))
                && type.GetCustomAttributes(false)
                .Any(attribute => attribute is ReferencesEnumAttribute
                                  && ((ReferencesEnumAttribute) attribute).AttributeType == attributeType))
            .ToArray();

    }
}

Upvotes: 1

Henrique
Henrique

Reputation: 610

It's not recomended using reflection in factory classes for it may cause performance problems to your code. Using reflection somewhere in your code you'll have to use Activator.CreateInstance() method and this cause performance issues to your app, look at this post: Does System.Activator.CreateInstance(T) have performance issues big enough to discourage us from using it casually?

Upvotes: 0

Related Questions