如果我有一个带有几个实现类的通用接口,例如:
public interface IDataElement<T>
{
int DataElement { get; set; }
T Value { get; set; }
}
public class IntegerDataElement : IDataElement<int>
{
public int DataElement { get; set; }
public int Value { get; set; }
}
public class StringDataElement : IDataElement<String>
{
public int DataElement { get; set; }
public String Value { get; set; }
}
是否可以传递不同类型的实现类的集合,而不必求助于作为对象传递。
似乎无法将返回值定义为
public IDataElement<T>[] GetData()
或
public IDataElement<object>[] GetData()
有什么建议吗?
答案 0 :(得分:4)
你当然可以声明:
public IDataElement<T>[] GetData<T>()
和
public IDataElement<object>[] GetData()
虽然后者可能不是您所追求的(即使在C#4中您的界面也不会变化,因为它在输入和输出位置都使用T
;即使它如果是变体,您将无法将该方差用于值类型)。前者将要求呼叫者指定<T>
,例如
foo.GetData<string>();
你可以吗?
没有办法表达“一个对象的集合,每个对象都为不同的T”实现IDataElement<T>
,除非你还给它一个非通用的基类,你可以使用IList<IDataElement>
。在这种情况下,非泛型IDataElement
可以具有DataElement
属性,将Value
属性保留在通用接口中:
public interface IDataElement
{
int DataElement { get; set; }
}
public interface IDataElement<T> : IDataElement
{
T Value { get; set; }
}
这在您的特定情况下有用吗?
目前尚不清楚如何在不知道其类型的情况下使用数据元素的集合......如果上述内容对您没有帮助,也许您可以更多地了解您对集合的期望。< / p>
答案 1 :(得分:3)
不,你不能这样做 - 唯一的选择是使用非通用接口:
public interface IDataElement
{
int DataElement { get; set; }
object Value { get; set; }
}
或者创建一个包装器并将其传递给知道所需类型的方法:
public class DataElementBag
{
private IDictionary<Type, List<object>> _elements;
...
public void Add<T>(IDataElement<T> de)
{
Type t = typeof(T);
if(!this._elements.ContainsKey(t))
{
this._elements[t] = new List<object>();
}
this._elements[t].Add(de);
}
public void IEnumerable<IDataElement<T>> GetElementsByType<T>()
{
Type t = typeof(T);
return this._elements.ContainsKey(t)
? this._elements[t].Cast<IDataElement<T>>()
: Enumerable.Empty<T>();
}
}
答案 2 :(得分:0)
不确定这是否对您的用例有所帮助,但是您可以在没有任何基础的基础/标签界面上
public interface IDataElement {}
并使您的Variant Generic Interface继承自该接口(如Jon Skeet所示)
public interface IDataElement<out T>
因此,您可以使用其互变的,非变型的通用接口(充满嘴巴)创建这些“对象”的集合
var collection = new List<IDataElement>(){ ... }
我认为,当您采用一个元素时,您可能必须有点明确,但对我而言,这就是C#类型安全性所在(C#非常明确!),并避免使用对象
IDataElement<MyType> value = List.First(x => DataElement == 12);
或者在显式转换时使用略带皱眉的
var element = (IDataElement<MyType>)List.First(x => DataElement == 12);
我之所以搜索这个问题,是因为我有一个像TTYpe Get<TType>()
这样的通用方法,因为我有点迷惑了Strategy / Visitor模式。我想通过使用泛型类型作为方法的参数来向提供者询问任意事情。
听起来可能有些奇怪,但实际上我可以利用依赖注入来注入任意数量的IDataElement实现,这些实现知道如何根据提供者自行配置...我想要做的只是
var sqlConnection = tenantProvider.Get<SqlConnection>();
var storageTyep = tenantProvider<StorageProvider>();
并具有泛型,变体泛型接口和标签接口的功能。强烈要求消费者使用,可以完成通用实现。
public TSetting GetSetting<TSetting>() where TSetting : class
{
var sp = tenantSettingsDictionary[typeof(TSetting)];
return sp as TSetting;
}