C#非通用ISet接口

时间:2019-04-17 17:06:41

标签: c# list set contravariance

.NET 4.0引入了非泛型IList,它公开了无需知道泛型类型即可向列表添加值的功能。这很有用,因为它允许我编写如下方法:

void CreateListFromBytes(IntPtr bytes, Type outputType, out object outputObject)
{
    Type elementType = outputType.GenericTypeArguments[0];
    int numberOfElements = ReadHeaderBytes(bytes);
    bytes += Marshal.SizeOf(typeof(int));

    IList outputList = (IList) Activator.CreateInstance(outputType);
    for (int i = 0; i < numberOfElements; i++)
    {
        object element = ReadDataBytes(bytes, elementType);
        bytes += Marshal.SizeOf(elementType);
        outputList.Add(element);
    }

    outputObject = outputList;
}

但是,当我尝试为HashSetISet实现具有相似样式的方法时,我找不到这样的非通用接口,它公开了Add()方法。

我想知道是否存在我可能错过的接口。如果不是,我想知道如何才能将元素添加到我肯定知道的对象Set中(因为我创建了Activator.CreateInstance()

1 个答案:

答案 0 :(得分:1)

我最终会使用几种辅助类型来构建集合:

interface ISetBuilder 
{
    void Add(object item);
    object Build();
}

class SetBuilder<T, TSet> : ISetBuilder where TSet : ISet<T>, new() 
{
    private readonly TSet _set = new TSet();

    public void Add(object item) 
    {
        if (!(item is T typedItem)) 
        {
            throw new ArgumentException();
        }

        _set.Add(typedItem);
    }

    public object Build() => _set;
}

然后可以像这样使用这些类型:

var builderType = typeof(SetBuilder<,>).MakeGenericType(elementType, outputType);
var builder = (ISetBuilder) Activator.CreateInstance(builderType);
var element = CreateElement(...);
builder.Add(element);
var set = builder.Build();

是的,这也可以推广到支持列表。只需将ISet<T>替换为ICollection<T>

另一种可能的(但不太健壮)的解决方案是使用反射来查找和调用集合的特定Add方法。