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

StackOverflow https://stackoverflow.com/questions/15491341

  •  24-03-2022
  •  | 
  •  

Question

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.

Était-ce utile?

La solution

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

Autres conseils

Use:

bool isHashSet = typeof(HashSet<object>).IsAssignableFrom(type);

or

object x = ...
HashSet<object> hs = x as HashSet<object>;
if (hs != null)
{
    // use hs
}

If you really have <T> specified then use it instead of object.


HashSet<T> implements ICollection<T>, IEnumerabel<T>, IEnumerable. What means if you know T you can both enumerate and add. Otherwise enumerate only enumerate.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top