字典签名如下:
Dictionary<TKey, TValue>
是否有可能以某种方式将新对象实例化为TValue
?
我知道我可以从那里调用一个方法或new
关键字,但我不能在那里有参数,我希望实例化的对象需要参数。
答案 0 :(得分:4)
由于TValue
没有限制是类或具有构造函数,因此没有安全的方法来“创建”实例({1}}可能是没有公共构造函数的类型!)
一种选择是使用default
:
TValue
将为引用类型返回var value = default(TValue);
,为数值类型返回null
,或者将每个成员初始化为默认值的结构。
您还可以从0
继承并添加Dictionary
具有默认构造函数的限制:
TValue
或在扩展方法中添加限制:
public class MyDict<TKey,TValue> : Dictionary<TKey, TValue> where TValue : new()
{
public void Add(TKey key)
{
this.Add(key, new TValue());
}
}
答案 1 :(得分: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
和反思魔法来美化一些事情......
<强>更新强>
但是我想的越多,代码看起来越人性化......我使用TValue Create(params object[] args)
,但我也可以介绍TValue Create(Func<TValue> giveBirth)
并使用它像
var human = humans.Create(() => new Human("Elvis", elvisMom, elvisDad));
Create方法的所有目的都只是在它喜欢的地方注入委托调用(例如在某个锁内) - 就像在ConcurrentDictionary.GetOrAdd Method中完成的那样