我有一本字典:
private Dictionary<Type, IExample> examples;
我有两个实现该接口的类:
public class Example1 : IExample
{
}
public class Example2 : IExample
{
}
我已经创建了一种从字典中获取实例的方法(如果它存在但是我试图找出一种方法来实例化一个新对象,如果它不存在的话。
public T GetExample<T>() where T : IExample
{
// Return the signal if it exists
if (examples.ContainsKey(typeof(T)))
{
IExample value;
if (!examples.TryGetValue(typeof(T), out value))
{
// unable to get value
}
return (T)value;
}
// Stuck on this line here. How exactly do I instantiate a new example if it doesn't exist.
examples.Add(typeof(T), new );
return default(T);
}
这样的事情可能吗?
答案 0 :(得分:13)
您需要在无参数构造函数的泛型方法上添加泛型类型参数约束,然后您可以实例化类型为T
的{{1}}类型参数:
new T()
和public T GetExample<T>() where T : IExample,class,new()
{
IExample value;
if (examples.TryGetValue(typeof(T), out value))
{
return (T)value;
}
T obj = new T(); // create instance of T and use further down in code it's reference
examples.Add(typeof(T),obj );
return obj ;
}
将返回return default(T);
而不是null
的新实例和类(引用类型)默认值为T
,i怀疑你想在那里做null
,这将创建一个新对象并将其引用返回给调用者。
答案 1 :(得分:8)
虽然你当然可以创建一个需要默认构造函数的类型约束,但它通常过于拘束:代码的用户可能不愿意将默认构造函数设为public,或者根本没有默认构造函数。
更灵活的方法是创建一个缺少对象的委托:
public T GetExample<T>(Func<T> make) where T : IExample, class {
IExample value;
if (examples.TryGetValue(typeof(T), out value)) {
return (T)value;
}
T res = make();
examples.Add(typeof(T), res);
return res;
}
这样,当您需要的对象未缓存在examples
中时,调用者可以控制如何创建新对象。您的代码“按需”回调,因此对象创建逻辑仍然隐藏在调用者的代码中,例如
var e = exampleFactory.GetExample<MyExample>(
() => new MyExample(firstParameter, secondParameter)
);
答案 2 :(得分:1)
您可以使用反射来实例化泛型类型:
var newInstance = return Activator.CreateInstance<T>();
正如Ehsan所说,你需要为类型T
添加一个约束,以便可以实例化它:where T: class
。
或者您添加new()
约束where T: new()
。然后你可以将它实例化为
var newInstance = new T();
答案 3 :(得分:1)
您可以使用建议的新约束@EhsanSajjad并为字典创建通用扩展方法:
public static class DictionaryExtensions
{
public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key) where TValue : new()
{
var exists = dictionary.TryGetValue(key, out var value);
if (!exists)
{
value = new TValue();
dictionary.Add(key, value);
}
return value;
}
}
out var
仅在您使用 C#7 时才有效,否则您必须拆分该行。
或者更好的是,您可以传递可选的默认值:
public static class DictionaryExtensions
{
public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue = null) where TValue : class, new()
{
var exists = dictionary.TryGetValue(key, out var value);
if (!exists)
{
value = defaultValue ?? new TValue();
dictionary.Add(key, value);
}
return value;
}
}
答案 4 :(得分:1)
扩展Ehsan的答案,我会怎样做:
public T GetExample<T>() where T : IExample,class,new()
{
IExample value;
if (!examples.TryGetValue(typeof(T), out value))
{
// Object doesn't exist. Create and add
value = new T();
examples.Add(typeof(T), value);
}
return (T)value;
}
同时使用ContainsKey
和TryGetValue
是多余的。