Подтвердить что ты не робот

Почему я не могу написать if (object is HashSet <>), но это нормально, если я пишу (object.GetType() == typeof (HashSet <>))

Название говорит все, здесь то же самое с некоторым форматированием:

Почему я не могу написать

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

но это нормально:

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

(То же самое относится к всем генерикам и не ограничивается HashSet)

4b9b3361

Ответ 1

Ваша функция

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

вернет false для каждого возможного значения obj, кроме null, и в этом случае он выкинет NullReferenceException. Он не проверяет, является ли obj хэш-набор. typeof(HashSet<int>) и typeof(HashSet<>) - два разных типа.

По той же причине, что obj is HashSet<> отклоняется. Это совершенно бесполезно. Единственная разница между этими двумя функциями заключается в том, что один бесполезен в том, как компилятор знает об этом, а другой бесполезен в способе, о котором компилятор не знает.

Вы можете использовать type.IsGenericType и type.GetGenericTypeDefinition(), а затем сравнить результат последнего с typeof(HashSet<>). Однако вы должны спросить себя, полезно ли это: obj is HashSet<int> также оценивает значение true, если obj выводится из HashSet<int>. Для работы с obj.GetType() потребуется проверить иерархию классов самостоятельно.

Вы можете написать многократно используемую вспомогательную функцию, чтобы проверить это для других общих типов:

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

Вы можете назвать это как IsInstanceOfGenericType(someObject, typeof(HashSet<>)).

Чтобы ответить на ваши комментарии:

В моем понимании HashSet<> будет означать HashSet любого общего, так что, возможно, это сработает typeof(HashSet<>).IsAssignableFrom(HashSet<int>)

Это не так. Возможно, вы думаете о Java, которая, как я понимаю, имеет что-то подобное, но С# этого не делает. HashSet<int> и HashSet<> являются родственными типами, но их отношение не связано с наследованием.

если нет значения HashSet<>

Это тип HashSet<T>, прежде чем он получит какой-либо конкретный аргумент типа. Его можно использовать для построения реальных типов, например, после var t = typeof(int);, typeof(HashSet<>).MakeGenericType(t) можно использовать для получения typeof(HashSet<int>). Это может быть полезно, если t не известно во время компиляции. Но вне такой конструкции динамического типа это не имеет смысла.

и почему это допустимо для записи в typeof(), но не в is HashSet<>?

Недействительно с is HashSet<>, потому что это никогда не будет значимым. Невозможно построить объект, тип которого HashSet<>.

Ответ 2

Ни один из них не работает, это просто то, что первый не будет работать во время компиляции. То, что вы, вероятно, хотите, это что-то вроде этого:

public bool IsHashSet(object obj)
{
    if (obj != null) 
    {
        var t = obj.GetType();
        if (t.IsGenericType) {
            return t.GetGenericTypeDefinition() == typeof(HashSet<>);
        }
    }
    return false;
}