在C#中:如何声明一个类型为key的通用Dictionary和该类型的IEnumerable 作为值?

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

 private IDictionary<Type, IEnumerable> _dataOfType where T: BaseClass; //does not compile! 

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

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

 IEnumerable concreteData; _sitesOfType.TryGetValue(typeof(ConcreteType), out concreteData); 

如何定义这样的字典?

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

 interface IBase {} static class Container { static class PerType where T : IBase { public static IEnumerable list; } public static IEnumerable Get() where T : IBase => PerType.list; public static void Set(IEnumerable newlist) where T : IBase => PerType.list = newlist; public static IEnumerable GetByExample(T ignoredExample) where T : IBase => Get(); } 

请注意,在采用此方法之前,您应该仔细考虑编译时类型和运行时类型之间的区别。 这个方法很乐意让你在SomeType下存储一个运行时类型的IEnumerable变量,如果你在SomeTypeSomeType类型(包括IBase运行它,既没有运行时也没有编译类型错误 – 这可能是function,或等待发生的错误,所以你可能想要if检查。

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

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

  ServiceContainer container = new ServiceContainer(); IList integers = new List(); IList strings = new List(); IList doubles = new List(); container.AddService(typeof(IEnumerable), integers); container.AddService(typeof(IEnumerable), strings); container.AddService(typeof(IEnumerable), doubles); 

你不限制私人成员的T ; 你在课堂上限制它。

 class Foo where T : BaseClass { private IDictionary> _dataOfType; public Foo(IDictionary> dataOfType) { this._dataOfType = dataOfType; } } 
  1. 您不能约束特定变量。 它只适用于类和方法。 说实话,它在变量级别中确实没有任何意义。
  2. 你想要的是一个自定义类 – class WeirdDictionary : IDictionary ,它将重载Add方法以获取Type和该类型的IEnumerable,你可以使用约束来做,并将IEnumerable <>转换为IEnumerable 。 重载索引器,并将其转换回相关类型。
    所有这些转换都是必需的,因为generics是严格的IEnumerableIEnumerable一样好(我相信这叫做方差?)

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

由280Z28编辑:

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

 class WeirdDictionary : IDictionary { private readonly Dictionary _data = new Dictionary(); public void Add(IEnumerable value) { _data.Add(typeof(T), value); } public bool TryGet(out IEnumerable value) { IEnumerable enumerable; if (_data.TryGetValue(typeof(T), out enumerable) { value = (IEnumerable)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.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); } } 

结束280Z28

创建一个自定义的Dictionary类:

 public class BaseClassDictionary> : Dictionary> where T : BaseClass { } 

然后您可以使用此专用字典作为字段类型:

 private BaseClassDictionary> myDictionary; 

试试这个:

 public class MyCustomDictionary: Dictionary> { }