例:

public static void DoSomething<K,V>(IDictionary<K,V> items) {
   items.Keys.Each(key => {
      if (items[key] **is IEnumerable<?>**) { /* do something */ }
      else { /* do something else */ }
}

这可以不使用反射吗? 我怎么说C#中的IEnumerable? 我应该只使用IEnumerable,因为IEnumerable <>实现IEnumerable?

===============>>#1 票数:106

非常感谢这篇文章。 我想提供一个对我来说效果更好的Konrad Rudolph解决方案。 我在该版本中遇到了一些小问题,特别是在测试Type是否为可为空的值类型时:

public static bool IsAssignableToGenericType(Type givenType, Type genericType)
{
    var interfaceTypes = givenType.GetInterfaces();

    foreach (var it in interfaceTypes)
    {
        if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
            return true;
    }

    if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
        return true;

    Type baseType = givenType.BaseType;
    if (baseType == null) return false;

    return IsAssignableToGenericType(baseType, genericType);
}

===============>>#2 票数:40 已采纳

以前接受的答案很好但是错了。 值得庆幸的是,错误很小。 如果你真的想知道接口的通用版本,检查IEnumerable是不够的; 有很多类只实现非泛型接口。 我会在一分钟内给出答案。 首先,我想指出接受的答案过于复杂,因为以下代码在给定的情况下会达到相同的效果:

if (items[key] is IEnumerable)

这甚至更多,因为它分别适用于每个项目(而不是它们的公共子类, V )。

现在,为了正确的解决方案。 这有点复杂,因为我们必须采用泛型类型IEnumerable`1 (即带有一个类型参数的类型IEnumerable<> )并注入正确的泛型参数:

static bool IsGenericEnumerable(Type t) {
    var genArgs = t.GetGenericArguments();
    if (genArgs.Length == 1 &&
            typeof(IEnumerable<>).MakeGenericType(genArgs).IsAssignableFrom(t))
        return true;
    else
        return t.BaseType != null && IsGenericEnumerable(t.BaseType);
}

您可以轻松地测试此代码的正确性:

var xs = new List<string>();
var ys = new System.Collections.ArrayList();
Console.WriteLine(IsGenericEnumerable(xs.GetType()));
Console.WriteLine(IsGenericEnumerable(ys.GetType()));

收益率:

True
False

不要过分担心这会使用反射。 虽然这是真的,这增加了运行时开销,因此不使用的is运营商。

当然,上面的代码非常有限,可以扩展为更普遍适用的方法IsAssignableToGenericType 以下实现略有不正确1 ,我将其留在这里仅用于历史目的 不要使用它 相反, 詹姆斯在他的回答中提供了一个优秀,正确的实现。

public static bool IsAssignableToGenericType(Type givenType, Type genericType) {
    var interfaceTypes = givenType.GetInterfaces();

    foreach (var it in interfaceTypes)
        if (it.IsGenericType)
            if (it.GetGenericTypeDefinition() == genericType) return true;

    Type baseType = givenType.BaseType;
    if (baseType == null) return false;

    return baseType.IsGenericType &&
        baseType.GetGenericTypeDefinition() == genericType ||
        IsAssignableToGenericType(baseType, genericType);
}

1genericTypegenericType相同时givenType ; 出于同样的原因,它可以为可空类型,即

IsAssignableToGenericType(typeof(List<int>), typeof(List<>)) == false
IsAssignableToGenericType(typeof(int?), typeof(Nullable<>)) == false

用一套全面的测试用例创建了一个要点

===============>>#3 票数:5

关于泛型类型和使用IsAssignableFrom()的警告......

说你有以下内容:

public class MyListBase<T> : IEnumerable<T> where T : ItemBase
{
}

public class MyItem : ItemBase
{
}

public class MyDerivedList : MyListBase<MyItem>
{
}

在基本列表类型或派生列表类型上调用IsAssignableFrom将返回false,但显然MyDerivedList继承MyListBase<T> (Jeff的快速说明,泛型绝对必须包含在代码块中或倾斜以获取<T> ,否则它被省略。这是有意吗?)问题源于MyListBase<MyItem>被视为完全的事实与MyListBase<T>不同的类型。 以下文章可以更好地解释这一点。 http://mikehadlow.blogspot.com/2006/08/reflecting-generics.html

相反,请尝试以下递归函数:

    public static bool IsDerivedFromGenericType(Type givenType, Type genericType)
    {
        Type baseType = givenType.BaseType;
        if (baseType == null) return false;
        if (baseType.IsGenericType)
        {
            if (baseType.GetGenericTypeDefinition() == genericType) return true;
        }
        return IsDerivedFromGenericType(baseType, genericType);
    }

/编辑:Konrad的新帖子考虑了通用递归以及接口。 非常好的工作。 :)

/ EDIT2:如果检查genericType是否是接口,则可以实现性能优势。 检查可以是当前接口代码的if块,但如果您对使用.NET 3.5感兴趣,我的一位朋友提供以下内容:

    public static bool IsAssignableToGenericType(Type givenType, Type genericType)
    {
        var interfaces = givenType.GetInterfaces().Where(it => it.IsGenericType).Select(it => it.GetGenericTypeDefinition());
        var foundInterface = interfaces.FirstOrDefault(it => it == genericType);
        if (foundInterface != null) return true;

        Type baseType = givenType.BaseType;
        if (baseType == null) return false;

        return baseType.IsGenericType ?
            baseType.GetGenericTypeDefinition() == genericType :
            IsAssignableToGenericType(baseType, genericType);
    }

===============>>#4 票数:4

if (typeof(IEnumerable).IsAssignableFrom(typeof(V))) {

===============>>#5 票数:4

感谢您提供的精彩信息。 为方便起见,我将其重构为扩展方法并将其简化为单个语句。

public static bool IsAssignableToGenericType(this Type givenType, Type genericType)
{
  return givenType.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == genericType) ||
         givenType.BaseType != null && (givenType.BaseType.IsGenericType && givenType.BaseType.GetGenericTypeDefinition() == genericType ||
                                        givenType.BaseType.IsAssignableToGenericType(genericType));
}

现在可以通过以下方式轻松调用:

sometype.IsAssignableToGenericType(typeof运算(MyGenericType <>))

===============>>#6 票数:1

我使用重载:

public static void DoSomething<K,V>(IDictionary<K,V> items)
  where V : IEnumerable
{
   items.Keys.Each(key => { /* do something */ });
}

public static void DoSomething<K,V>(IDictionary<K,V> items)
{
   items.Keys.Each(key => { /* do something else */ });
}

===============>>#7 票数:0

我曾经认为这种情况可能以类似于@Thomas Danecker的解决方案的方式解决 ,但添加了另一个模板参数:

public static void DoSomething<K, V, U>(IDictionary<K,V> items)
    where V : IEnumerable<U> { /* do something */ }
public static void DoSomething<K, V>(IDictionary<K,V> items)
                             { /* do something else */ }

但我现在注意到它不起作用,除非我明确指定第一个方法的模板参数。 这显然不是根据字典中的每个项目定制的,但它可能是一种穷人的解决方案。

如果有人能指出我在这里可能做的任何不正确的事情,我将非常感激。

===============>>#8 票数:0

我不确定我明白你的意思。 您想知道对象是否是任何泛型类型,或者您想测试它是否是特定的泛型类型 或者你只是想知道是否可以枚举?

我不认为第一个是可能的。 第二个肯定是可能的,只需将其视为任何其他类型。 对于第三个,只需按照你的建议对IEnumerable进行测试。

此外,您不能在类型上使用'is'运算符。

// Not allowed
if (string is Object)
  Foo();
// You have to use 
if (typeof(object).IsAssignableFrom(typeof(string))
  Foo();

有关详细信息,请参阅有关类型的此问题 也许它会帮助你。

===============>>#9 票数:0

您想要查看Type.IsInstanceOfType方法

  ask by Chris Bilson translate from so

未解决问题?本站智能推荐:

2回复

是否可以将引用传递给另一种类型的通用对象?

我有一个方法,我想接受引用特定对象: 然后我有: 一个通用对象,可以是动物和其他东西。 如果它是一个动物我想将目标投射到动物然后将该参考传递给我的死亡方法,但我无法弄清楚如何做到这一点......
1回复

通过动态将一种通用(值)类型转换为另一种类型(值)是否涉及装箱/拆箱?

鉴于: 我正在尝试编写一种通用方法,该方法可用于将一种类型强制转换或转换为另一种类型,因此: 在第一行中,我需要首先强制转换为(object)或(dynamic)以避免编译器错误“无法将类型'TInput'转换为'TOutput'”。 我明白了,例如从这个 ,在使用dyna
2回复

StructureMap:将(通用)实现连接到另一种类型的实现

如果我有一个界面: 还有一个抽象类: 以及IRepository / LinqToSqlRepository的一整套实现(例如AccountRepository,ContactRepository等),使用StructureMap(2.5.3)通常将它们全部连接起来的最佳方法是什
4回复

如何将通用数组转换为另一种类型?

我仍然试图找到一种快速的方法来如何将TOutput类型的通用数组转换为另一个类型为TInput的数组。 我的所有数组都是数字数据类型,但由于C#对经常请求的数字没有类型约束,所以我目前不得不忍受这种约束。 建议的方法,比如之前投射到一个物体,似乎极大地减慢了我的演员阵容。 目前我有一个大的
3回复

将一种类型的通用列表转换为另一种类型,其中仅在运行时知道这些类型

本质上,我正在寻找一种将GenericList<TInput>转换为GenericList<TOutput> ,其中GenericList是实现特定接口的任何类型的泛型列表,并且TInput和TOutput类型仅在运行时已知。 下面是可以执行此操作的类和方法的片段,
2回复

将控件从一种类型切换到另一种类型?

我不确定如何正确地称呼标题,但这是这种情况: 我们有一个庞大的解决方案,其中包含约130个项目。 代码中有一些冗余,即我们创建的特定LookupButton控件。 由于某种原因,不是在所有模块化项目都引用的Infrastructure.CommonControls项目中创建此Looku
1回复

在MVC中将一种类型转换为另一种类型

我有两个参考: 在.Core参考中,我有一类具有业务功能的类。 在另一个模型中-模型,视图和控制器。 我想做一个简单的Crete函数,但是不能转换类型。
1回复

将一种类型的列表转换为另一种类型

我有以下课程: 我需要将列表“ MovimentacaoECF_Id.TotalizadoresParciais ”转换为其他列表... 当我在字典中转换KeyPairValue时,我可能会报告列表一的X字段是列表二的Y字段
3回复

将一种类型转换为另一种类型

我怎样才能在上面 我收到此错误: 无法将类型为'System.Data.Entity.DynamicProxies.MainType_F04DC499C53D433B05ABEDEE7191583DB11728F68B18671613EF0E5AC158DD0D'的对象强制转
1回复

将一种类型的列表映射到另一种类型

对于我的对象,我使用的是Csla,它具有BrokenRulesCollection属性。 我想将它转换为我自己的具有StatusMessages属性的DTO。 我创建了自己的解析器: 在映射中,我让它知道要使用哪个解析器: 但是,当我尝试进行映射时: 我收到以下错