在C#中:如何声明类型为键的通用字典和该类型的IEnumerable <>作为值?

Mar*_*cel 26 c# generics dictionary types

我想声明一个存储IEnumerable特定类型的类型的字典,并将其确切类型作为键,如下所示:(编辑后跟随johny g的评论)

private IDictionary<Type, IEnumerable<T>> _dataOfType where T: BaseClass; //does not compile!
Run Code Online (Sandbox Code Playgroud)

我想要存储的具体类都是从BaseClass派生的,因此想把它当作约束.编译器抱怨它希望在成员名称后面加一个分号.

如果它可以工作,我希望这将使后来从字典中检索简单如下:

IEnumerable<ConcreteData> concreteData;
_sitesOfType.TryGetValue(typeof(ConcreteType), out concreteData);
Run Code Online (Sandbox Code Playgroud)

如何定义这样的字典?

thi*_*eek 25

使用System.ComponentModel.Design.ServiceContainer.Net框架中已有的.

        ServiceContainer container = new ServiceContainer();

        IList<int> integers = new List<int>();
        IList<string> strings = new List<string>();
        IList<double> doubles = new List<double>();

        container.AddService(typeof(IEnumerable<int>), integers);
        container.AddService(typeof(IEnumerable<string>), strings);
        container.AddService(typeof(IEnumerable<double>), doubles);
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的答案,使用框架中已有的内容. (2认同)

Eam*_*nne 16

您甚至可能不需要字典才能做到这一点 - 但这取决于您的需求.如果每个appdomain每个类型只需要1个这样的列表(即"字典" static),则以下模式可以高效并且很好地促进类型推断:

interface IBase {}

static class Container {
    static class PerType<T> where T : IBase {
        public static IEnumerable<T> list;
    }

    public static IEnumerable<T> Get<T>() where T : IBase 
        => PerType<T>.list; 

    public static void Set<T>(IEnumerable<T> newlist) where T : IBase 
        => PerType<T>.list = newlist;

    public static IEnumerable<T> GetByExample<T>(T ignoredExample) where T : IBase 
        => Get<T>(); 
}
Run Code Online (Sandbox Code Playgroud)

请注意,在采用此方法之前,您应该仔细考虑编译时类型和运行时类型之间的区别.这个方法很乐意让你存储一个运行时类型的IEnumerable<SomeType>变量SomeType,如果你把它放在任何基SomeType类型下,包括IBase既没有运行时也没有编译类型错误 - 这可能是一个特性,或者是等待的bug发生了,所以你可能想要if检查一下.

此外,这种方法忽略了线程; 所以如果你想从多个线程访问这个数据结构,你可能想要添加一些锁定.引用读/写是原子的,因此如果你无法锁定,你就不会受到损害,但是过时的数据和竞争条件肯定是可能的.


Mar*_*off 11

你不限制T私人会员; 你在课堂上限制它.

class Foo<T> where T : BaseClass
{
    private IDictionary<T, IEnumerable<T>> _dataOfType;

    public Foo(IDictionary<T, IEnumerable<T>> dataOfType)
    {
        this._dataOfType = dataOfType;
    }   
}   
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的,也可能是它不编译的原因.然而,这不是我想要的,我想有一个类型约束成员,但不是类的类型约束. (7认同)

Rub*_*bys 7

  1. 您不能约束特定变量.它只适用于类和方法.说实话,它在变量级别中确实没有任何意义.
  2. 你想要的是一个自定义类 - class WeirdDictionary : IDictionary<Type, IEnumerable>它将重载Add方法以获取Type和该类型的IEnumerable,你可以使用约束来做,并将IEnumerable <>强制转换为IEnumerable.重载索引器,并将其转换回相关类型.
    需要所有这些铸造,因为泛型是严格大约IEnumerable<Base>是一样好IEnumerable<Derived>(这就是所谓的差异,我相信吗?)

这种解决方案略有概括,因为重用岩石

由280Z28编辑:

起初我把它标记下来,因为第2点令人困惑,我误解了它.通过在方法中使用显式实现方法IDictionary<Type, IEnumerable>并提供通用替代方法,您可以获得非常干净的接口.请注意,您无法创建通用索引器,因此您必须始终使用TryGet<T>(无论如何这都是个好主意).我只包括显式实现其中一个IDictionary<>方法来显示如何执行检查.不要WeirdDictionary直接派生,Dictionary<Type, IEnumerable>否则您将无法保证基础数据中的约束.

class WeirdDictionary : IDictionary<Type, IEnumerable>
{
    private readonly Dictionary<Type, IEnumerable> _data =
        new Dictionary<Type, IEnumerable>();

    public void Add<T>(IEnumerable<T> value)
    {
        _data.Add(typeof(T), value);
    }

    public bool TryGet<T>(out IEnumerable<T> value)
    {
        IEnumerable enumerable;
        if (_data.TryGetValue(typeof(T), out enumerable)
        {
            value = (IEnumerable<T>)enumerable;
            return true;
        }

        value = null;
        return false;
    }

    // use explicit implementation to discourage use of this method since
    // the manual type checking is much slower that the generic version above
    void IDictionary<Type, IEnumerable>.Add(Type key, IEnumerable value)
    {
        if (key == null)
            throw new ArgumentNullException("key");
        if (value != null && !typeof(IEnumerable<>).MakeGenericType(key).IsAssignableFrom(value.GetType()))
            throw new ArgumentException(string.Format("'value' does not implement IEnumerable<{0}>", key));

        _data.Add(key, value);
    }
}
Run Code Online (Sandbox Code Playgroud)

结束280Z28

  • 我对所提供的280Z28实现进行了一些测试,它适用于所有类,并且效果很好.这是一个整洁,奇怪的想法. (2认同)