How to loop through a HashSet<T> when it is provided as an object and the T can be anything?

Jeff Treuting picture Jeff Treuting · Mar 19, 2013 · Viewed 11.9k times · Source

I'm using Value Injecters to map from 1 type to another using the LoopValueInjection and overriding the SetValue(object v) method with some custom logic. I am trying to detect when a HashSet is being passed in and go through the HashSet and apply a method to each item in it to do some clean up. The issues I'm having are because the parameter is just an object and I don't know what the type of item will be in the HashSet. For example, it could be HashSet or HashSet.

Here is the code I currently have but I'm getting an InvalidCastException.

    protected override object SetValue(object v)
    {
        if (type.Name == "HashSet`1")
        {
            var genericType = type.GetGenericArguments()[0];

            // this line throws the InvalidCastException 
            var cleanHashSet = (HashSet<object>)Activator.CreateInstance(type);

            foreach (var item in (HashSet<object>)v)  // I'm sure this cast will throw as well
            {
                cleanHashSet.Add(Clean(item));
            }

            return cleanHashSet;
        }

        return base.SetValue(v);
    }

I guess the main question is how can I loop through the HashSet that is passed in as an object once I determine it is in fact a HashSet of some kind? I'm also thinking I will need to create a new empty HashSet of the specific type as well so I can put each item that gets cleaned up into it.

Answer

hazzik picture hazzik · Mar 19, 2013

In .NET only interfaces and delegate types can be co- and contra-variant. So it is not possible to cast HashSet<SomeType> to HashSet<object>.

You want to cast your v to non-generic version of IEnumerable interface

dynamic cleanHashSet = Activator.CreateInstance(type);
foreach (object item in (IEnumerable)v)
{
    cleanHashSet.Add(Clean(item)); 
}

If you don't want to use dynamic keyword then you need to call Add method with reflection

object cleanHashSet = Activator.CreateInstance(type);
var method = type.GetMethod("Add");
foreach (object item in (IEnumerable)v)
{
    method.Invoke(cleanHashSet, new object[] { Clean(item) });
}