C # неуниверсальный интерфейс ISet - PullRequest
2 голосов
/ 17 апреля 2019

.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;
}

Однако, когда я пытаюсь реализовать метод с похожим стилем для HashSet или ISet, неттакой неуниверсальный интерфейс я могу найти, который выставляет и метод Add().

Мне интересно, существует ли такой интерфейс, который я, возможно, пропустил.Если нет, мне интересно, как я могу добавить элементы к объекту, который я точно знаю, это Set (поскольку я создал его Activator.CreateInstance())

1 Ответ

1 голос
/ 17 апреля 2019

Я бы закончил с парой вспомогательных типов для построения набора:

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 метод набора с помощью отражения.

...