Bart Kerfeld
Bart Kerfeld

Reputation: 1045

C# Non-Generic ISet Interface

.NET 4.0 introduced a non-generic IList which exposes the ability to add values to the List without needing to know the generic type. This is useful because it allows me to write a method such as the following:

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

However, when I try to implement a method with a similar style for HashSet or ISet, there is not such non-generic interface I can find that exposes and Add() method.

I am wondering if such an interface exists that I may have missed. If not, I am wondering how I can go about adding elements to object I know for certain is Set (since I created it the Activator.CreateInstance())

Upvotes: 2

Views: 990

Answers (1)

tukaef
tukaef

Reputation: 9214

I would end up with a couple of aux types for constructing a set:

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

Those types then could be used like this:

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

And yes, this could be generalised to support lists as well. Just replace ISet<T> with ICollection<T>.

Another possible (but a bit less robust) solution is just to find and call the specific Add method of a set by using reflection.

Upvotes: 1

Related Questions