Why can't I write if (object is HashSet<>) but it's okay if I write (object.GetType() == typeof(HashSet<>))

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

  •  12-07-2023
  •  | 
  •  

Domanda

The title says it all, here's the same with some formatting:

Why can't I write

public bool IsHashSet(object obj)
{
    return obj is HashSet<>;
}

but this is okay:

public bool IsHashSet(object obj)
{
    return obj.GetType() == typeof(HashSet<>);
}

(The same goes for all generics and isn't limited to HashSet)

È stato utile?

Soluzione

Your function

public bool IsHashSet(object obj)
{
  return obj.GetType() == typeof(HashSet<>);
}

will return false for every possible value of obj, except null, in which case it will throw a NullReferenceException. It will not check if obj is a hash set. typeof(HashSet<int>) and typeof(HashSet<>) are two different types.

It is for that same reason that obj is HashSet<> is rejected. It's completely useless. The only difference between the two functions is that one is useless in a way the compiler knows about, and the other is useless in a way the compiler doesn't know about.

You can use type.IsGenericType and type.GetGenericTypeDefinition(), then compare the result of the latter to typeof(HashSet<>). However, you should ask yourself if that is useful: obj is HashSet<int> would also evaluate to true if obj is derived from HashSet<int>. Working with obj.GetType() would require you to check the class hierarchy yourself.

You can write a reusable helper function to check this for other generic types too:

public static bool IsInstanceOfGenericType(object obj, Type genericType) {
  if (obj == null)
    return false;

  var type = obj.GetType();
  while (type != null) {
    if (type.IsGenericType && type.GetGenericTypeDefinition() == genericType)
      return true;

    type = type.BaseType;
  }
  return false;
}

You can call this as IsInstanceOfGenericType(someObject, typeof(HashSet<>)).

To respond to your comments:

In my understanding of HashSet<> would mean HashSet of any generic, so maybe this would work typeof(HashSet<>).IsAssignableFrom(HashSet<int>)

It would not. It's possible you're thinking of Java, which as I understand it does have something like that, but C# does not. HashSet<int> and HashSet<> are related types, but their relation is not one related to inheritance.

if not whats the meaning of HashSet<>

It is the HashSet<T> type before it has got any specific type argument. It can be used to construct the real types, for example after var t = typeof(int);, typeof(HashSet<>).MakeGenericType(t) can be used to get typeof(HashSet<int>). It can be useful if t is not known at compile-time. But outside of such dynamic type construction, it is not meaningful.

and why is it valid to write in a typeof() but not in is HashSet<>?

It's not valid with is HashSet<> because it would never be meaningful. It is impossible to construct any object whose type is HashSet<>.

Altri suggerimenti

Neither actually works, it's just that the first one will fail at compile time. What you probably want is something like this:

public bool IsHashSet(object obj)
{
    if (obj != null) 
    {
        var t = obj.GetType();
        if (t.IsGenericType) {
            return t.GetGenericTypeDefinition() == typeof(HashSet<>);
        }
    }
    return false;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top