C# - 添加实现接口到字典的对象

时间:2017-04-20 08:09:10

标签: c# dictionary generics

我有一本字典:

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

这样的事情可能吗?

5 个答案:

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

同时使用ContainsKeyTryGetValue是多余的。