在C#中:如何声明一个类型为key和IEnumerable的泛型词典<&燃气轮机;作为价值的那种类型?

在C#中:如何声明一个类型为key和IEnumerable的泛型词典<&燃气轮机;作为价值的那种类型?,c#,generics,dictionary,types,C#,Generics,Dictionary,Types,我想声明一个字典,它存储特定类型的键入的IEnumerable,并将该确切类型作为键,如下所示:(编辑以跟随johny g的注释) 私有IDictionary\u数据类型,其中T:BaseClass//不编译! 我要存储的具体类都是从基类派生的,因此我想将其用作约束。编译器抱怨在成员名称后需要一个分号 如果可行,我希望这将使以后从字典中检索变得简单,如: IEnumerable<ConcreteData> concreteData; _sitesOfType.TryGetValue

我想声明一个字典,它存储特定类型的键入的
IEnumerable
,并将该确切类型作为键,如下所示:(编辑以跟随johny g的注释)

私有IDictionary\u数据类型,其中T:BaseClass//不编译!
我要存储的具体类都是从基类派生的,因此我想将其用作约束。编译器抱怨在成员名称后需要一个分号

如果可行,我希望这将使以后从字典中检索变得简单,如:

IEnumerable<ConcreteData> concreteData;
_sitesOfType.TryGetValue(typeof(ConcreteType), out concreteData);
IEnumerable数据;
_sitesOfType.TryGetValue(typeof(ConcreteType),out concreteData);

如何定义这样的词典?

您不需要在私有成员中约束
t
;您可以在类级别约束它

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

    public Foo(IDictionary<T, IEnumerable<T>> dataOfType)
    {
        this._dataOfType = dataOfType;
    }   
}   
class Foo其中T:BaseClass
{
私有IDictionary_数据类型;
公共Foo(IDictionary数据类型)
{
这是.\u dataOfType=dataOfType;
}   
}   

创建自定义词典类:

public class BaseClassDictionary<T, IEnumerable<T>> : Dictionary<T, IEnumerable<T>>
    where T : BaseClass
{
}
公共类基类字典:字典
其中T:BaseClass
{
}
然后,您可以使用此专用字典作为字段类型:

private BaseClassDictionary<BaseClassDerivedType, IEnumerable<BaseClassDerivedType>> myDictionary;
私有BaseClassDictionary myDictionary;
  • 不能约束特定变量。它只适用于类和方法。老实说,这在变量层面上真的没有任何意义
  • 您需要的是一个自定义类-
    class-WeirdDictionary:IDictionary
    ,它将重载Add方法以获取该类型的类型和IEnumerable,您可以使用约束执行此操作,并将IEnumerable强制转换为IEnumerable。也重载索引器,并将其转换回相关类型。
    所有这些转换都是需要的,因为泛型严格要求
    IEnumerable
    IEnumerable
    一样好(我相信这就是所谓的差异?)
  • 由于重复使用岩石,此解决方案稍微通用

    由280Z28编辑:

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

    类古怪词典:IDictionary
    {
    专用只读字典\u数据=
    新字典();
    公共无效添加(IEnumerable值)
    {
    _数据。添加(类型(T),值);
    }
    公共bool TryGet(输出IEnumerable值)
    {
    IEnumerable可枚举;
    if(_data.TryGetValue(类型(T),out可枚举)
    {
    值=(IEnumerable)可枚举;
    返回true;
    }
    值=空;
    返回false;
    }
    //使用显式实现来阻止使用此方法,因为
    //手动类型检查比上面的通用版本慢得多
    void IDictionary.Add(类型键,IEnumerable值)
    {
    if(key==null)
    抛出新的ArgumentNullException(“键”);
    if(value!=null&&!typeof(IEnumerable).MakeGenericType(key).IsAssignableFrom(value.GetType())
    抛出新的ArgumentException(string.Format(“'value'不实现IEnumerable”,key));
    _数据。添加(键、值);
    }
    }
    
    结束280Z28

    试试这个:

    public class MyCustomDictionary<T>: Dictionary<T, IEnumerable<T>>  { } 
    
    公共类MyCustomDictionary:Dictionary{}
    
    您甚至可能不需要字典来实现这一点,但这取决于您的需要。如果您在每个appdomain中每种类型只需要一个这样的列表(即“字典”是
    静态的
    ),以下模式可以很有效地促进类型推断:

    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>(); 
    }
    
    接口IBase{}
    静态类容器{
    静态类PerType,其中T:IBase{
    公共静态IEnumerable列表;
    }
    公共静态IEnumerable Get(),其中T:IBase
    =>PerType.list;
    公共静态无效集(IEnumerable newlist),其中T:IBase
    =>PerType.list=newlist;
    公共静态IEnumerable GetByExample(T IgnoreExample),其中T:IBase
    =>Get();
    }
    
    请注意,在采用这种方法之前,您应该仔细考虑编译时类型和运行时类型之间的区别。这种方法可以让您愉快地将运行时类型的
    IEnumerable
    变量存储在
    SomeType
    下,如果您将其强制转换为
    SomeType
    的任何基本类型下,包括
    IBase
    ,既没有运行时错误,也没有编译类型错误-这可能是一个功能,也可能是一个等待发生的错误,因此您可能需要一个
    if
    来检查这一点

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

    使用中已经提供的.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);
    
    ServiceContainer=newServiceContainer();
    IList整数=新列表();
    IList strings=新列表();
    IList doubles=新列表();
    AddService(typeof(IEnumerable),整数);
    AddService(typeof(IEnumerable),字符串);
    container.AddService(typeof(IEnumerable),双精度);
    
    common约束类型,声明
    IDictionary
    将键约束为
    T
    的实例,而不是
    typeof(T)
    
    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>(); 
    }
    
            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);