说我有这样的方法:
public void Foo(object arguments)
并说我需要检测arguments
的类型是否实际上是枚举。我会写这样的东西:
if (arguments is IEnumerable)
现在,假设我需要检测它是否是KeyValuePair的枚举(无论键的类型和值的类型如何)。我的直觉是写这样的东西:
if (arguments is IEnumerable<KeyValuePair<,>>)
但是visual studio抱怨Using the generic type 'KeyValuePair<TKey, TValue>' requires 2 type arguments
。
我也尝试过:
if (arguments is IEnumerable<KeyValuePair<object, object>>)
但如果键不是一个对象(例如string
),或者该值不是一个对象(例如int
),则返回false。 / p>
是否有人建议如何确定枚举是否包含KeyValuePairs,无论密钥类型和值类型如何,如果是,我如何循环这些对?
答案 0 :(得分:1)
您可以将反射与GetGenericTypeDefinition
var pair = new KeyValuePair<string, int>("asd", 123);
var isOf = pair.GetType().GetGenericTypeDefinition() == typeof(KeyValuePair<,>);
注意:如果它不是通用类型,它将抛出异常
InvalidOperationException
当前类型不是通用类型。也就是说,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();
}}
<强>用法强>
var blah = Get2(list, typeof(KeyValuePair<,>));
注意:这一切真的取决于你想做什么,很难 告诉我,以上这些都只是不知道的愚蠢的例子 事先键入,可能无法满足您的需求。
其他信息
答案 1 :(得分:1)
你需要反思一下:
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;
}
}
为了重建Enumerable
并对其进行迭代,您可以使用以下使用dynamic
的方法:
List<KeyValuePair<Object, Object>> list = new List<KeyValuePair<Object, Object>>();
foreach (dynamic kvp in (IEnumerable)arguments)
list.Add(new KeyValuePair<Object, Object>(kvp.Key, kvp.Value));
或,LINQ
:
List<KeyValuePair<Object, Object>> list = (from dynamic kvp in (IEnumerable)arguments select new KeyValuePair<Object, Object>(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));
}
}
}
参考文献:
答案 2 :(得分:0)
感谢@ tommaso-belluzzo和@sarumanfor投入时间帮我解决这个问题。我最终接受了Tommaso的回答,因为我非常喜欢他使用dynamic
类型来枚举枚举中的项目的想法。
我也想提供我的解决方案(主要基于Tommasso的建议)
/// <summary>Get the key=>value pairs represented by a dictionary, enumeration of KeyValue pairs or an anonymous object.</summary>
private IEnumerable<KeyValuePair<string, object>> GetArguments(object arguments)
{
// null
if (arguments == null)
return Enumerable.Empty<KeyValuePair<string, object>>();
// dictionary
if (arguments is IDictionary dictionary)
return dictionary
.Cast<dynamic>()
.Select(item => new KeyValuePair<string, object>(item.Key.ToString(), item.Value));
// enumeration
if (arguments is IEnumerable enumeration)
{
#if NETFULL
var argumentsType = enumeration.GetType();
var itemType = argumentsType.GetElementType();
var isGeneric = itemType.IsGenericType;
var enumeratedType = isGeneric ? itemType.GetGenericTypeDefinition() : null;
#else
var argumentsTypeInfo = enumeration.GetType().GetTypeInfo();
var itemTypeInfo = argumentsTypeInfo.GetElementType().GetTypeInfo();
var isGeneric = itemTypeInfo.IsGenericType;
var enumeratedType = isGeneric ? itemTypeInfo.GetGenericTypeDefinition() : null;
#endif
if (enumeratedType == typeof(KeyValuePair<,>))
{
return enumeration
.Cast<dynamic>()
.Select(item => new KeyValuePair<string, object>(item.Key.ToString(), item.Value));
}
else
{
throw new ArgumentException("You must provide an enumeration of KeyValuePair", nameof(arguments));
}
}
// object
return arguments.GetType()
.GetRuntimeProperties()
.Where(p => p.CanRead)
.Select(p => new KeyValuePair<string, object>(p.Name, p.GetValue(arguments)));
}