通用接口列表

时间:2010-01-11 21:35:24

标签: c# generics interface

如果我有一个带有几个实现类的通用接口,例如:

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

有什么建议吗?

3 个答案:

答案 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;
 }