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