0

How do I create a class instance using known attributes? In this the attributes are values of an enum.

public enum MyEnum
{
    Value1,
    Value2
}

class MyAttribute : Attribute... //attribute definition class
{ //uses the enum}

//Main
abstract class MyMain ... 
{
     public static MyMain CreateClass
     {
        MyMain newInheritedClass = ?
     }
}

[MyAttribute(MyEnum.Value1)]
class MyClassA : MyMain ...

[MyAttribute(MyEnum.Value2)]
class MyClassB : MyMain ...
6
  • You could use Reflection for this but what are you really trying to achieve? There's probably a better way to do this. Commented Sep 10, 2016 at 17:12
  • I've got enum values stored and need to create the corresponding class based on the enum in question. Hence: calling the constructor with MyEnum.Value1 would return a new instance of MyClassA. Commented Sep 10, 2016 at 17:14
  • Yes, that is obvious from your question. But why do you need to do this? Is this design yours? Do you control MyMain and derived classes or are they third party or code you can't change? Commented Sep 10, 2016 at 17:16
  • All classes are mine. I'd like to create new derived classes against new enum values in the future and override certain functions in the base class in these derived classes. Commented Sep 10, 2016 at 17:22
  • Then you probably shouldn't be using this approach unless you are maybe thinking in some kind of plugin arquitecture. Nonetheless, I'll post an answer on how you'd do this. Commented Sep 10, 2016 at 17:40

2 Answers 2

2

I competely agree with Fabio's answer in that using attributes seems an overkill here but we don't have enough information to really know why you are using this approach so I'll show you how it would be done:

Your method CreateClass should look like this:

public static MyMain CreateClass(MyEnum value)
{
    var targetType = Assembly.GetExecutingAssembly()
                             .GetTypes()
                             .Where(t => t.IsSubclassOf(typeof(MyMain)) &&
                                    t.GetCustomAttribute<MyAttribute>()?.Value == value)
                             .FirstOrDefault();

    if (targetType != null)
        return Activator.CreateInstance(targetType) as MyMain;

    return null;
}

This presuposes two things:

  1. Your derived classes are defined in the executing assembly.
  2. Your derived classes have public parameterless constructors.

If niether is the case you can still adapt the solution investigating a little.

Sign up to request clarification or add additional context in comments.

1 Comment

If the CreateClass is getting called often I'd really recommend only executing GetTypes() once and then cache the relevant types (ie subclasses of the parent class which are non-abstract).
0

For the purposes you describe in comments I think using attributes is little bid overkill.
Just create a static method or factory class with method which will do the same things:

public static MyMain CreateInstance(MyEnum attribute)
{
    if(attribute == MyEnum.Value1)
    {
        return new MyClassA();
    }
    else
    {
        //...
    }
}

Of course if you have a task to create instance based on the attributes then:

private readonly Dictionary<MyEnum, Type> _Data;

public Factory(Assembly assembly) 
{
    var myAttributeClasses = 
        assembly.GetTypes()
                .Select(t => new 
                {
                    DirevedType = t,
                    Attribute = (MyAttribute)t.GetCustomAttribute(typeof(MyAttribute))
                })
                .Where(data => data.Attribute != null);

    _Data = new Dictionary<MyEnum, Type>();
    foreach(var data in myAttributeClasses)
    {
        _Data.Add(data.Attribute.EnumValue, data.DerivedType);
    }
}

public MyMain CreateInstance(MyEnum enumvalue)
{
    Type derivedType;
    if(_Data.TryGetValue(enumvalue, out derivedType) == false) 
        return null;

    return Activator.CreateInstance(derivedType);
}

4 Comments

I should've said this in the first place, but I want to keep the base class constructor clean of ifs, switches etc. and get the class instances using a structure that's free of these kind of statements.
@KSav what base class constructor? You are puttting "ifs and switches" in a factory method. And whatever is wrong with "ifs and switches"? This is programming...its like saying I want to go swimming but I don't want to get wet...
@KSav, anyway in somewhere you need to put if or switch at least once. So again Factory approach is good based on the information you gave us. Using attributes is vary good approach for creating plugin possibilities for your application, for example Microsoft have Managed Extensibility Framework (MEF) framework, which using "attribute programming"
Thanks guys. Managed to get a poc to work. Using cache really speeds up creating new instances.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.