我想声明一个字典,用于存储特定类型的类型IEnumerable
,并将该确切类型作为键,如下所示:(编辑后跟随johny g的评论)
private IDictionary<Type, IEnumerable<T>> _dataOfType where T: BaseClass; //does not compile!
我想要存储的具体类,都来自BaseClass,因此想把它当作约束。编译器抱怨它希望在成员名之后加一个分号。
如果它可以工作,我希望这会使后来从字典中检索简单如下:
IEnumerable<ConcreteData> concreteData;
_sitesOfType.TryGetValue(typeof(ConcreteType), out concreteData);
如何定义这样的字典?
答案 0 :(得分:25)
使用.Net框架中已有的System.ComponentModel.Design.ServiceContainer
。
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);
答案 1 :(得分:15)
您甚至可能不需要字典才能执行此操作 - 但这取决于您的需求。如果每个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>();
}
请注意,在采用此方法之前,您应该仔细考虑编译时类型和运行时类型之间的区别。此方法很乐意让您在IEnumerable<SomeType>
下存储运行时类型的SomeType
变量,如果您在SomeType
的任何IBase
基类型下投放它,则包括if
既没有运行时也没有编译类型错误 - 这可能是一个功能,或者等待发生的错误,所以你可能需要{{1}}来检查它。
此外,这种方法忽略了线程;所以如果你想从多个线程访问这个数据结构,你可能想要添加一些锁定。引用读/写是原子的,因此如果你无法锁定,你就不会受到损害,但是当然可能存在过时的数据和竞争条件。
答案 2 :(得分:11)
您不会在私人会员中约束T
;你在课堂上限制它。
class Foo<T> where T : BaseClass
{
private IDictionary<T, IEnumerable<T>> _dataOfType;
public Foo(IDictionary<T, IEnumerable<T>> dataOfType)
{
this._dataOfType = dataOfType;
}
}
答案 3 :(得分:7)
class WeirdDictionary : IDictionary<Type, IEnumerable>
,它将重载Add方法以获取Type和该类型的IEnumerable,你可以使用约束来做,并转换IEnumerable&lt;&gt;到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);
}
}
结束280Z28
答案 4 :(得分:4)
制作自定义词典类:
public class BaseClassDictionary<T, IEnumerable<T>> : Dictionary<T, IEnumerable<T>>
where T : BaseClass
{
}
然后您可以将此专用字典用作字段类型:
private BaseClassDictionary<BaseClassDerivedType, IEnumerable<BaseClassDerivedType>> myDictionary;
答案 5 :(得分:1)
试试这个:
public class MyCustomDictionary<T>: Dictionary<T, IEnumerable<T>> { }