2016-09-10 95 views
0

如何使用已知屬性創建類實例? 在這個屬性是一個枚舉的值。C#如何通過類屬性創建類實例

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 ... 
+0

你可以使用[Reflection](https://msdn.microsoft.com/en-us/library/mt656691.aspx),但你真的想要達到什麼目的?可能有更好的方法來做到這一點。 – InBetween

+0

我已經枚舉值存儲和需要創建相應的類基於問題的枚舉。因此:使用MyEnum.Value1調用構造函數將返回一個MyClassA的新實例。 – KSav

+0

是的,你的問題很明顯。但爲什麼你需要這樣做?這是你的設計嗎?你是否控制'MyMain'和派生類,或者他們是第三方還是你不能改變的代碼? – InBetween

回答

0

我與Fabio's answer一致認爲,使用屬性似乎是一個矯枉過正的地方,但我們沒有足夠的信息真正知道你爲什麼使用這種方法,所以我會告訴你它將如何完成:

你的方法應該是這樣的CreateClass

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; 
} 

這presuposes兩件事情:

  1. 你的派生類中執行的程序集定義。
  2. 您的派生類具有公共無參數構造函數。

如果你是這種情況,你仍然可以調整一下解決方案。

+1

如果'CreateClass'經常被調用,我真的建議只執行'GetTypes()'一次,然後緩存相關類型(即非抽象父類的子類)。 – flindeberg

+0

@flindeberg是的,這將是一個好主意。 – InBetween

0

爲了您在評論中描述的目的,我認爲使用屬性是小投標過度殺傷。
剛剛創建的方法靜態方法或工廠類,將做同樣的事情:如果你有一個任務,根據當時的屬性來創建實例

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

當然:

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); 
} 
+0

我應該首先說這個,但我想保持基類構造函數清理ifs,switch等,並使用一個沒有這些類型語句的結構來獲取類實例。 – KSav

+0

@KSav什麼是基類構造函數?你在工廠方法中使用「ifs和switch」。並且「ifs和switch」有什麼問題?這是編程...它就像說我想去游泳,但我不想被弄溼... – InBetween

+0

@ksav,無論如何你需要把'if或者switch'至少放一次。所以再次工廠方法是基於你給我們的信息。使用屬性是爲您的應用程序創建插件可能性的好方法,例如Microsoft擁有[Managed Extensibility Framework(MEF)](https://msdn.microsoft.com/en-us/library/dd460648(v = vs.110) )。aspx)框架,它使用「屬性編程」 – Fabio