Ответ 1
Это будет самая простая проверка.
if(Obj is ICollection)
{
//Derived from ICollection
}
else
{
//Not Derived from ICollection
}
Я хочу определить, является ли тип типа типа универсального типа ( "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<>)
Это будет самая простая проверка.
if(Obj is ICollection)
{
//Derived from ICollection
}
else
{
//Not Derived from ICollection
}
Вы можете использовать Type.GetInterface() с измененным именем.
private bool IsTAnEnumerable<T>(T x)
{
return null != typeof(T).GetInterface("IEnumerable`1");
}
Чтобы получить фактический тип 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
Лично я склонен использовать метод, который я написал сам, называемый 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<>) or typeof(IDictionary<,>).</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;
}
Я бы тестировал IEnumerable
вместо этого, так как тип коллекции мог реализовать только IEnumerable
, ему не нужно реализовывать IEnumerable<T>
.
Это также зависит: что вы имеете в виду с типом коллекции? У вас может быть коллекция без реализации каких-либо из этих интерфейсов.
Кроме того, помните только, что вы используете дженерики, не забывайте и другие базовые методы, в данном случае, как перегрузка. Я подозреваю, что вы планируете что-то вроде этого:
void SomeFunc<T>(T t)
{
if (IsCollectionCase(t))
DoSomethingForCollections()
else
DoSOmethingElse();
}
Это будет гораздо лучше, если:
void SomeFunc(IEnumerable t)
{
DoSomethingForCollections()
}
void SomeFunc<T>(T t)
{
DoSomethingElse()
}
Пока я не могу быть уверен в том, что было в оригинальном намерении плаката, было несколько ответов на вопрос о влиянии литья на IEnumerable для тестирования. Это прекрасно, но все должны знать, что экземпляры строк проходят этот тест, что может и не быть чем-то оригинальным автором. Я знаю, что, конечно, не сделал, когда пошел искать ответ и нашел этот пост:
string testString = "Test";
Console.WriteLine(testString as IEnumerable != null); // returns true
Я пытаюсь написать собственный сериализатор, который использует отражение для выполнения определенных задач. В рамках задачи мне нужно определить, является ли значение свойства коллекцией/массивом/списком элементов или единственным значением свойства. Что особенно раздражает, так это то, что несколько выражений Linq фактически приводят к перечисляемому типу значения, но GetType(). IsArray возвращает false для них, а их вывод в ICollection также возвращает значение null, но приведение их в IEnumerable возвращает ненулевое значение.
Итак... пока я все еще ищу решение, которое работает для всех случаев.
Мне нравятся дженерики. В этом методе T
должен иметь открытый и бесступенчатый конструктор, что означает, что вы не можете использовать IList<object>
для T
. Вы должны использовать List<object>
public static T IsEnumerable<T>() where T : new() {
if (new T() is IEnumerable) {
}
Я столкнулся с той же проблемой при попытке сериализации любого объекта в формате 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...
}