2014-01-29 71 views
0

的字典簽名是這樣的:詞典新對象TValue

Dictionary<TKey, TValue> 

是否有可能,不知何故,實例化一個新的對象爲TValue

我知道我可以從那裏調用一個方法或new關鍵字,但是我不能在那裏有參數,我希望實例化需要參數的對象。

+0

做在什麼情況你有做一本字典,你不知道值類型? –

回答

4

既然沒有限制,即TValue是一個類或有一個構造函數,有「創造」的情況下沒有安全的方式(它可能是TValue是不具有公共構造類型!)

一一種選擇是使用default

var value = default(TValue); 

將返回null對於引用類型,0數值類型,或初始化爲它的每個成員的struct的默認。

您也可以繼承Dictionary並添加限制條件爲TValue有一個默認的構造函數:在一個擴展方法

public class MyDict<TKey,TValue> : Dictionary<TKey, TValue> where TValue : new() 
{ 
    public void Add(TKey key) 
    { 
     this.Add(key, new TValue()); 
    } 
} 

或添加限制:

public static class Ext 
{ 
    public static void Add<TKey, TValue>(this Dictionary<TKey, TValue> d, TKey key) where TValue : new() 
    { 
     d.Add(key, new TValue()); 
    } 
} 
+0

我同意在具有其類型的參數沒有限制字典貴點,但'TValue'可能取決於使用它(因爲你沒有實例化無法解決的類型參數的字典可)範圍內有限制。如果您在具有與(例如)'類,新的()'的限制,同一類型的'TValue'參數時,那麼你可以做一個'新TValue()的通用參數的函數使用'。但是就原始問題而言,沒有類型參數的限制,暗示某個具有已定義參數的構造函數。 –

+0

@SimonBelanger同意 - 請參閱我的編輯。 –

1

既然你有沒有澄清了上下文,我想象了一個帶有內部Dictionary<TKey, TValue>存儲空間的工作方法以及一個工作方法,其中包含任意數量的參數:

public class Beings<TValue> 
{ 
    private readonly Dictionary<long, TValue> dictionary; 
    private readonly Func<object[], TValue> giveBirth; 

    public Beings(Func<object[], TValue> giveBirth) 
    { 
     this.dictionary = new Dictionary<long, TValue>(); 
     this.giveBirth = giveBirth; 
    } 

    public TValue Create(params object[] args) 
    { 
     var newBeing = this.giveBirth(args); 
     this.dictionary[this.dictionary.Count] = newBeing; 

     return newBeing; 
    } 
} 

請注意,它的構造函數需要一個Func<object[], TValue>委託 - TValue中的任何對象。

接下來想象兩個衆生的例子:人類和克隆人。人類通常有媽媽和爸爸,克隆人只有原始的人類。因此,我們有類,如:

[DebuggerDisplay("{Name}")] 
public class Human 
{ 
    public Human(string name, Human mom, Human dad) 
    { 
     this.Name = name; 
     this.Mom = mom; 
     this.Dad = dad; 
    } 

    public string Name { get; private set; } 
    public Human Mom { get; private set; } 
    public Human Dad { get; private set; } 
} 

public class HumanClone : Human 
{ 
    public HumanClone(Human original) 
     : base(original.Name + "_Clone", null, null) 
    { 
     this.Original = original; 
    } 

    public Human Original { get; private set; } 
} 

現在,我們通過Beings<Human>Beings<HumanClone>隔離我們的生活的物種,建立工廠代表們Func<object[], TValue>簽名:

Func<object[], Human> humanGiveBirth = humanBirthArgs => 
    new Human(name: (string)humanBirthArgs[0], mom: (Human)humanBirthArgs[1], dad: (Human)humanBirthArgs[2]); 

var humans = new Beings<Human>(humanGiveBirth); 

Func<object[], HumanClone> humanCloneGiveBirth = humanCloneBirthArgs => 
    new HumanClone(original: (Human)humanCloneBirthArgs[0]); 

var humanClones = new Beings<HumanClone>(humanCloneGiveBirth); 

而對於測試我們的宇宙我們創造了一些物種:

var human1 = humans.Create("Adam", null, null); 
var human2 = humans.Create("Eva", null, null); 
var human3 = humans.Create("Kain", human2, human1); 
var human4 = humans.Create("Avel", human2, human1); 

var humanClone1 = humanClones.Create(human1); 
var humanClone2 = humanClones.Create(human2); 

缺點是您沒有構造函數參數的智能感知,您還必須在工廠代理定義中明確地鍵入轉換每個對象arg。 可能是你可以美化一些事情Delegate.CreateDelegate和反射魔法......

UPDATE:

但我認爲它的越多,人工代碼看起來...我用TValue Create(params object[] args),但我還不如引進TValue Create(Func<TValue> giveBirth)和使用它像

var human = humans.Create(() => new Human("Elvis", elvisMom, elvisDad)); 

,創造方法的所有目的是隻注入則委託調用它喜歡的(一些鎖內,例如) - 就像是在ConcurrentDictionary.GetOrAdd Method