C# 将对象转换为 IEnumerable<T> 并在可枚举类型为值类型时使用 Linq 扩展,例如枚举
C# Cast object to IEnumerable<T> and use Linq extensions when the enumerable type is a value type e.g. enum
如果我知道类型是可枚举类型?
对 IEnumerable<object>
的简单转换适用于引用类型,但不适用于枚举等值类型,例如:
StringComparison[] myArray = new StringComparison[] {
StringComparison.OrdinalIgnoreCase,
StringComparison.Ordinal
};
void DoSomething(object value) {
IEnumerable<object> items = (IEnumerable<object>) value;
// use the enumerable with System.Linq.Enumerable extensions
// items.Count()
// items.Distinct()
}
DoSomething(myArray);
对于枚举,演员会抛出 System.InvalidCastException: 'Unable to cast object of type 'System.StringComparison[]' to type 'System.Collections.Generic.IEnumerable^1[System.Object]'.'
其他答案(例如 C# object to array)建议通过强制转换为非泛型 IEnumerable
来实现此目的。不幸的是,我想要的扩展方法(Count()
和 Distinct()
)不适用于非泛型 IEnumerable
.
背景:上面的例子是经过简化的。我的实际用例是我编写了一个自定义 System.ComponentModel.DataAnnotations.ValidationAttribute
,它对可枚举属性 属性 执行检查。 ValidationAttribute
有一个方法 IsValid(object value)
,枚举值数组被传递给该方法,我需要迭代该方法 属性 但由于这个原因它失败了。
谢谢!
数组StringComparison[]
实现了IEnumerable
和IEnumerable<StringComparison>
接口,但没有实现IEnumerable<object>
.
不幸的是,您不能使用泛型协变来将 IEnumerable<StringComparison>
类型的对象分配给 IEnumerable<object>
类型的变量,因为 StringComparison
不是引用类型: 你不能像访问对象一样访问 StringComparison[]
的任何旧元素,因为它没有正常的对象头等
你可以做的是:
IEnumerable<object> items = ((IEnumerable)value).Cast<object>();
之所以有效,是因为数组实现了 IEnumerable
,而 Enumerable.Cast
是 IEnumerable
上的扩展方法,而不是 IEnumerable<T>
。
每次从 items
获取元素时,Cast<object>()
方法都会参与并将 StringComparison
值类型装箱到一个对象中。
这意味着多次迭代列表(因为调用大量 linq 方法会这样做)可能很昂贵,因为它每次都会分配新对象。您可能希望将盒装对象缓存到列表中以避免此成本:
List<object> items = ((IEnumerable)value).Cast<object>().ToList();
如果我知道类型是可枚举类型?
对 IEnumerable<object>
的简单转换适用于引用类型,但不适用于枚举等值类型,例如:
StringComparison[] myArray = new StringComparison[] {
StringComparison.OrdinalIgnoreCase,
StringComparison.Ordinal
};
void DoSomething(object value) {
IEnumerable<object> items = (IEnumerable<object>) value;
// use the enumerable with System.Linq.Enumerable extensions
// items.Count()
// items.Distinct()
}
DoSomething(myArray);
对于枚举,演员会抛出 System.InvalidCastException: 'Unable to cast object of type 'System.StringComparison[]' to type 'System.Collections.Generic.IEnumerable^1[System.Object]'.'
其他答案(例如 C# object to array)建议通过强制转换为非泛型 IEnumerable
来实现此目的。不幸的是,我想要的扩展方法(Count()
和 Distinct()
)不适用于非泛型 IEnumerable
.
背景:上面的例子是经过简化的。我的实际用例是我编写了一个自定义 System.ComponentModel.DataAnnotations.ValidationAttribute
,它对可枚举属性 属性 执行检查。 ValidationAttribute
有一个方法 IsValid(object value)
,枚举值数组被传递给该方法,我需要迭代该方法 属性 但由于这个原因它失败了。
谢谢!
数组StringComparison[]
实现了IEnumerable
和IEnumerable<StringComparison>
接口,但没有实现IEnumerable<object>
.
不幸的是,您不能使用泛型协变来将 IEnumerable<StringComparison>
类型的对象分配给 IEnumerable<object>
类型的变量,因为 StringComparison
不是引用类型: 你不能像访问对象一样访问 StringComparison[]
的任何旧元素,因为它没有正常的对象头等
你可以做的是:
IEnumerable<object> items = ((IEnumerable)value).Cast<object>();
之所以有效,是因为数组实现了 IEnumerable
,而 Enumerable.Cast
是 IEnumerable
上的扩展方法,而不是 IEnumerable<T>
。
每次从 items
获取元素时,Cast<object>()
方法都会参与并将 StringComparison
值类型装箱到一个对象中。
这意味着多次迭代列表(因为调用大量 linq 方法会这样做)可能很昂贵,因为它每次都会分配新对象。您可能希望将盒装对象缓存到列表中以避免此成本:
List<object> items = ((IEnumerable)value).Cast<object>().ToList();