C# 如何在不知道键的类型和值的类型的情况下遍历KeyValuePair的枚举

C# 如何在不知道键的类型和值的类型的情况下遍历KeyValuePair的枚举,c#,C#,假设我有这样一种方法: public void Foo(object arguments) if (arguments is IEnumerable) if (arguments is IEnumerable<KeyValuePair<,>>) 假设我需要检测参数的类型是否实际上是一个枚举。我会这样写: public void Foo(object arguments) if (arguments is IEnumerable) if (arguments is

假设我有这样一种方法:

public void Foo(object arguments)
if (arguments is IEnumerable)
if (arguments is IEnumerable<KeyValuePair<,>>)
假设我需要检测
参数的类型是否实际上是一个枚举。我会这样写:

public void Foo(object arguments)
if (arguments is IEnumerable)
if (arguments is IEnumerable<KeyValuePair<,>>)
现在,假设我需要检测它是否是KeyValuePair的枚举(不管键的类型和值的类型)。我的直觉是这样写:

public void Foo(object arguments)
if (arguments is IEnumerable)
if (arguments is IEnumerable<KeyValuePair<,>>)
if(参数是IEnumerable)
但是VisualStudio抱怨说,
使用泛型类型“KeyValuePair”需要两个类型参数

我还尝试:

if (arguments is IEnumerable<KeyValuePair<object, object>>)
if(参数是IEnumerable)
但如果键不是对象(例如
字符串
),或者值不是对象(例如
int
),则返回false


有人建议我如何确定枚举是否包含KeyValuePairs,而不考虑键类型和值类型,如果是,我如何循环这些对?

您可以使用反射
GetGenericTypeDefinition

var pair = new KeyValuePair<string, int>("asd", 123);

var isOf = pair.GetType().GetGenericTypeDefinition() == typeof(KeyValuePair<,>);
当前类型不是泛型类型。也就是说,IsGenericType返回 错

您可以使用
Type.IsGenericType

我不确定你是否真的想在这里实现

foreach

private bool Get<T>(IEnumerable<T> list, Type someType) 
{
   foreach (var item in list)
   {
      if (item.GetType()
               .GetGenericTypeDefinition() == someType)
      {
         return true;
      }
   }
   return false;
}

private List<T> Get2<T>(IEnumerable<T> list, Type someType)
{
   return list.Where(
         item => item.GetType()
                     .GetGenericTypeDefinition() == someType)
      .ToList();
}}
private bool Get(IEnumerable list,键入someType)
{
foreach(列表中的变量项)
{
if(item.GetType()
.GetGenericTypeDefinition()==someType)
{
返回true;
}
}
返回false;
}
私有列表Get2(IEnumerable列表,键入someType)
{
返回列表。在哪里(
item=>item.GetType()
.GetGenericTypeDefinition()==someType)
.ToList();
}}
用法

var blah = Get2(list, typeof(KeyValuePair<,>));
var blah=Get2(列表,类型(KeyValuePair));
注意:所有这些都取决于你想做什么,很难做到 告诉我,以上两个都只是不知道答案的愚蠢例子 事先输入,可能无法满足您的需要

其他信息


您需要在此进行反思:

Boolean isKeyValuePair = false;

Type type = arguments.GetType();

if (type.IsGenericType)
{
    Type[] genericTypes = type.GetGenericArguments();

    if (genericTypes.Length == 1)
    {
        Type underlyingType = genericTypes[0];

        if (underlyingType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
            isKeyValuePair = true;
    }
}
或者,使用
LINQ

List<KeyValuePair<Object, Object>> list = (from dynamic kvp in (IEnumerable)arguments select new KeyValuePair<Object, Object>(kvp.Key, kvp.Value)).ToList();
List List=(从(IEnumerable)参数中的动态kvp选择新的KeyValuePair(kvp.Key,kvp.Value)).ToList();
我还找到了另一个解决方案,但这纯粹是疯狂:

Boolean isKeyValuePair = false;

Type type = arguments.GetType();

if (type.IsGenericType)
{
    Type[] genericTypes = type.GetGenericArguments();

    if (genericTypes.Length == 1)
    {
        Type underlyingType = genericTypes[0];

        if (underlyingType.GetGenericTypeDefinition() == typeof (KeyValuePair<,>))
        {
            Type[] kvpTypes = underlyingType.GetGenericArguments();

            Type kvpType = typeof(KeyValuePair<,>);
            kvpType = kvpType.MakeGenericType(kvpTypes);

            Type listType = typeof (List<>);
            listType = listType.MakeGenericType(kvpType);

            dynamic list = Activator.CreateInstance(listType);

            foreach (dynamic argument in (IEnumerable)arguments)
                list.Add(Activator.CreateInstance(kvpType, argument.Key, argument.Value));
        }
    }
}
布尔isKeyValuePair=false;
Type Type=arguments.GetType();
if(type.IsGenericType)
{
类型[]genericTypes=Type.GetGenericArguments();
if(genericTypes.Length==1)
{
类型UnderlineType=genericTypes[0];
if(underlyngType.GetGenericTypeDefinition()==typeof(KeyValuePair))
{
Type[]kvpTypes=underyingtype.GetGenericArguments();
类型kvpType=类型(KeyValuePair);
kvpType=kvpType.MakeGenericType(kvpTypes);
类型listType=typeof(列表);
listType=listType.MakeGenericType(kvpType);
动态列表=Activator.CreateInstance(listType);
foreach(IEnumerable参数中的动态参数)
添加(Activator.CreateInstance(kvpType,argument.Key,argument.Value));
}
}
}
参考资料:


    • 感谢@tommaso belluzzo和@sarumanfor花时间帮助我解决这个问题。我最终接受了Tommaso的答案,因为我非常喜欢他使用
      动态
      类型枚举枚举中的项的想法

      我还想贡献我的解决方案(主要基于Tommasso的建议)

      ///获取由字典、键值对枚举或匿名对象表示的键=>值对。
      私有IEnumerable GetArguments(对象参数)
      {
      //空的
      if(参数==null)
      返回可枚举的.Empty();
      //字典
      if(参数是IDictionary字典)
      返回字典
      .Cast()
      .Select(item=>newkeyvaluepair(item.Key.ToString(),item.Value));
      //列举
      if(参数为IEnumerable枚举)
      {
      #如果未满
      var argumentsType=enumeration.GetType();
      var itemType=ArgumentType.GetElementType();
      var isGeneric=itemType.isgenericype;
      var enumeratedType=isGeneric?itemType.GetGenericTypeDefinition():null;
      #否则
      var argumentsTypeInfo=enumeration.GetType().GetTypeInfo();
      var itemTypeInfo=argumentsTypeInfo.GetElementType().GetTypeInfo();
      var isGeneric=itemTypeInfo.IsGenericType;
      var enumeratedType=isGeneric?itemTypeInfo.GetGenericTypeDefinition():null;
      #恩迪夫
      if(enumeratedType==typeof(KeyValuePair))
      {
      返回枚举
      .Cast()
      .Select(item=>newkeyvaluepair(item.Key.ToString(),item.Value));
      }
      其他的
      {
      抛出新ArgumentException(“您必须提供KeyValuePair的枚举”,nameof(arguments));
      }
      }
      //反对
      返回参数。GetType()
      .GetRuntimeProperties()
      .其中(p=>p.CanRead)
      .Select(p=>newkeyvaluepair(p.Name,p.GetValue(arguments)));
      }
      
      以防万一这是一个XY问题(),您能告诉我们您试图解决的根本问题吗?“有人建议我如何确定枚举是否包含KeyValuePairs,而不考虑键类型和值类型吗?”--显而易见的选项是反射。但你的问题并不清楚,也没有证据表明你进行过研究或尝试过任何有成效的事情。正如您所发现的,C#不支持开放泛型类型……需要在编译时知道该类型。因此,即使您确定枚举包含
      KeyValuePair
      实例,您会如何处理它们?请即兴表演