在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
一样好(我相信这就是所谓的差异?)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);