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

Определить, возникает ли объект из типа коллекции

Я хочу определить, является ли тип типа типа универсального типа ( "T" ) типом коллекции. Обычно я отправлял T через Generic.List, но это мог быть любой тип коллекции, поскольку это используется в вспомогательной функции.

Было бы лучше проверить, реализует ли он IEnumerable <T> ?

Если да, то каким будет выглядеть код?

Обновление 14:17 GMT + 10 Возможно расширение на решение здесь (однако работает только для List <T> not IEnumerable <T> , когда это необходимо, если List получает?)

T currentObj;    
// works if currentObj is List<T>
currentObj.GetType().GetGenericTypeDefinition() == typeof(List<>)
// does not work if currentObj is List<T>
currentObj.GetType().GetGenericTypeDefinition() == typeof(IEnumerable<>)
4b9b3361

Ответ 1

Это будет самая простая проверка.

if(Obj is ICollection)
{
    //Derived from ICollection
}
else
{
    //Not Derived from ICollection
}

Ответ 2

Вы можете использовать Type.GetInterface() с измененным именем.

private bool IsTAnEnumerable<T>(T x)
{
    return null != typeof(T).GetInterface("IEnumerable`1");
}

Ответ 3

Чтобы получить фактический тип T во время выполнения, вы можете использовать выражение typeof (T). Оттуда нормальные операторы сравнения типов будут делать трюк

bool isEnumerable = typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));

Код полного кода:

static bool Foo<T>()
{
  return typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
}

Foo<List<T>>();  // true
Foo<int>(); // false

Ответ 4

Лично я склонен использовать метод, который я написал сам, называемый TryGetInterfaceGenericParameters, который я разместил ниже. Вот как использовать его в вашем случае:

Пример использования

object currentObj = ...;  // get the object
Type[] typeArguments;
if (currentObj.GetType().TryGetInterfaceGenericParameters(typeof(IEnumerable<>), out typeArguments))
{
    var innerType = typeArguments[0];
    // currentObj implements IEnumerable<innerType>
}
else
{
    // The type does not implement IEnumerable<T> for any T
}

Здесь важно отметить, что вы проходите в typeof(IEnumerable<>), не typeof(IEnumerable) (это совсем другой тип), а также не typeof(IEnumerable<T>) для any T (если вы уже знаете T, вам не нужен этот метод). Конечно, это работает с любым общим интерфейсом, например. вы можете использовать typeof(IDictionary<,>) (но не typeof(IDictionary)).

Источник метода

/// <summary>
///     Determines whether the current type is or implements the specified generic interface, and determines that
///     interface generic type parameters.</summary>
/// <param name="type">
///     The current type.</param>
/// <param name="interface">
///     A generic type definition for an interface, e.g. typeof(ICollection&lt;&gt;) or typeof(IDictionary&lt;,&gt;).</param>
/// <param name="typeParameters">
///     Will receive an array containing the generic type parameters of the interface.</param>
/// <returns>
///     True if the current type is or implements the specified generic interface.</returns>
public static bool TryGetInterfaceGenericParameters(this Type type, Type @interface, out Type[] typeParameters)
{
    typeParameters = null;

    if (type.IsGenericType && type.GetGenericTypeDefinition() == @interface)
    {
        typeParameters = type.GetGenericArguments();
        return true;
    }

    var implements = type.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == @interface, null).FirstOrDefault();
    if (implements == null)
        return false;

    typeParameters = implements.GetGenericArguments();
    return true;
}

Ответ 5

Я бы тестировал IEnumerable вместо этого, так как тип коллекции мог реализовать только IEnumerable, ему не нужно реализовывать IEnumerable<T>.

Это также зависит: что вы имеете в виду с типом коллекции? У вас может быть коллекция без реализации каких-либо из этих интерфейсов.

Ответ 6

Кроме того, помните только, что вы используете дженерики, не забывайте и другие базовые методы, в данном случае, как перегрузка. Я подозреваю, что вы планируете что-то вроде этого:

void SomeFunc<T>(T t)
{
    if (IsCollectionCase(t))
       DoSomethingForCollections()
    else
       DoSOmethingElse();
}

Это будет гораздо лучше, если:

void SomeFunc(IEnumerable t)
{
       DoSomethingForCollections()
}
void SomeFunc<T>(T t)
{
       DoSomethingElse()
}

Ответ 7

Пока я не могу быть уверен в том, что было в оригинальном намерении плаката, было несколько ответов на вопрос о влиянии литья на IEnumerable для тестирования. Это прекрасно, но все должны знать, что экземпляры строк проходят этот тест, что может и не быть чем-то оригинальным автором. Я знаю, что, конечно, не сделал, когда пошел искать ответ и нашел этот пост:

string testString = "Test";
Console.WriteLine(testString as IEnumerable != null);  // returns true

Я пытаюсь написать собственный сериализатор, который использует отражение для выполнения определенных задач. В рамках задачи мне нужно определить, является ли значение свойства коллекцией/массивом/списком элементов или единственным значением свойства. Что особенно раздражает, так это то, что несколько выражений Linq фактически приводят к перечисляемому типу значения, но GetType(). IsArray возвращает false для них, а их вывод в ICollection также возвращает значение null, но приведение их в IEnumerable возвращает ненулевое значение.

Итак... пока я все еще ищу решение, которое работает для всех случаев.

Ответ 8

Мне нравятся дженерики. В этом методе T должен иметь открытый и бесступенчатый конструктор, что означает, что вы не можете использовать IList<object> для T. Вы должны использовать List<object>

public static T IsEnumerable<T>() where T : new() {
    if (new T() is IEnumerable) {
}

Ответ 9

Я столкнулся с той же проблемой при попытке сериализации любого объекта в формате JSON. Вот что я в итоге использовал:

Type typ = value.GetType();

// Check for array type
if(typeof(IEnumerable).IsAssignableFrom(typ) || typeof(IEnumerable<>).IsAssignableFrom(typ))
{ 
    List<object> list = ((IEnumerable)value).Cast<object>().ToList();
    //Serialize as an array with each item in the list...
}
else
{
    //Serialize as object or value type...
}