2009-08-15 104 views
4

比方說,我有基類FooParent,它有大量的FooChildren。在運行時,我必須創建一個FooChildren之一的實例。我將如何做到這一點?我意識到我可以創建一個巨大的地圖(並使用代表)或一個巨大的switch/case聲明,但這似乎有點草率。在類似PHP,我可以輕鬆地動態地創建一個類是這樣的:.NET中的動態類初始化

$className="FooClass"; 
$myNewFooClass=new $className; //makes a new instance of FooClass 

(你也可以做到這一點使用反射)。

.NET有這樣的東西嗎?反思是一種選擇,是否有任何表現處罰?如果不是,我還有什麼其他選擇?

類的類型將由JSON請求確定。該變量可以是我想要的任何東西..如果我想要做一個枚舉,它可以是一個整數,或者它可以是完整的類名。我還沒有創建它,所以我還沒決定。

+0

查找「Activator.CreateInstance」。 – 2009-08-15 19:41:00

+0

該類是否總是有一個無參數的構造函數? – 2009-08-15 20:11:07

回答

8

如果你真的想要,你可以用反射來做,但會有性能懲罰。它們是否重要取決於你的確切情況。正如你所建議的那樣,根據你想要做的事情,我很可能會使用switch/case語句或地圖。尤其是,如果您需要根據您構建的類型將不同的參數傳遞給不同的構造函數,那麼這將非常有用 - 通過反射來實現這一點會有點痛苦,因爲您已經是特殊框架的不同類型。


編輯:好的,所以我們現在知道總會有一個無參數的構造函數。在這種情況下,你的JSON可以很容易地包含在類名沒有命名空間(如果他們都在同一個命名空間)和你的方法可能是這個樣子:

public FooParent CreateFoo(string name) 
{ 
    if (name == null) 
    { 
     throw new ArgumentNullException("name"); 
    } 
    string fullName = "Some.NameSpace." + name; 
    // This is assuming that the type will be in the same assembly 
    // as the call. If that's not the case, we can look at that later. 
    Type type = Type.GetType(fullName); 
    if (type == null) 
    { 
     throw new ArgumentException("No such type: " + type); 
    } 
    if (!typeof(FooParent).IsAssignableFrom(type)) 
    { 
     throw new ArgumentException("Type " + type + 
            " is not compatible with FooParent."); 
    } 
    return (FooParent) Activator.CreateInstance(type); 
} 

你在哪裏確定名稱使用?

public FooParent CreateFoo(string name) 
{ 
    switch (name) 
    { 
     case "Foo1":  return new Foo1(); 
     case "Foo2":  return new Foo2(); 
     case "Foo3":  return new Foo3(); 
     case "Foo4":  return new Foo4(); 
     case "FooChild1": return new FooChild1(); 
     default: 
      throw new ArgumentException("Unknown Foo class: " + name); 
    } 
} 

你要知道,剛剛寫了出來,我不知道它有什麼實際的好處(比其他:如果在某處真實過去了,重新格式化從規範稍微離開時,switch語句可以很簡單性能)優於使用Type.GetType(name),然後使用Activator.CreateInstance(type)

來電者如何知道要通過的類名?這絕對是動態的嗎?有沒有可能使用泛型?你可以告訴我們有關情況的信息越多,我們就可以得到更多幫助。

+0

我更新了我的帖子,希望能更清楚一點。 – ryeguy 2009-08-15 20:08:04

+0

是的,這個類將始終有一個無參數的構造函數。 – ryeguy 2009-08-16 00:10:35

2
yourvar = Activator.CreateInstance(Type.GetType("foo.bar.Baz")); 
3

只要你所有的FooChildren都有無參數的構造函數,你可以用反射來做到這一點。

Activator.CreateInstance<FooChildType>(); 

如果實際上沒有該類型的引用,你已經是與類的名稱的字符串,你可以這樣做:

Activator.CreateInstance("FooChildClassName", "Fully.Qualified.AssemblyName"); 

有性能損失反思,但如果這對你來說是最簡單的解決方案,並且你的表現是可以接受的,我不會掛斷它。

0

如果您關心性能,還有另一種選擇。使用

Type yourType = Type.GetType("FooClass"); 

獲取您的班級的類型。現在你可以使用

ConstructorInfo ctor = yourType.GetConstructor(new Type[0]); 

得到你的構造函數的構造函數信息。如果您不想使用默認構造函數,請將要傳遞給構造函數的類型數組傳遞給它。現在你可以使用這樣的構造函數:

object instanceOfFooClass = ctor.Invoke(new object[0]); 

前兩個步驟只能執行一次。您可以保存「ctor」以備後用。調用Activator.CreateInstance應該會更快。