首页 > 解决方案 > 从对象访问 Array(任何元素类型)的元素

问题描述

我使用管理来访问设备属性,并在下面编写了一个代码来创建一个字典数组。listview我的应用程序在控件中显示属性;所以我需要将所有属性值转换为简单的字符串

Dictionary<string,string>[] getInfo(string k) {
    // using `k` as management-key
    var mos = new ManagementObjectSearcher($"select * from {k}");
    var devices = new List<Dictionary<string, string>>();
    var mosc = mos.Get();    // mosc is a collection of all devices with same key
    foreach (var device in mosc) {
        var properties = new Dictionary<string, string>();
            foreach (var p in device.Properties) {
                if (p.Value != null) {
                    if (p.IsArray) {
                        // I have problem in here
                        // my application must convert p.value to string
                        var collection = (IEnumerable<object>)p.Value
                        properties[p.Name] = string.Join(", ", collection.Select(x=>x.ToString()));
                    } else
                        properties[p.Name] = p.Value.ToString();
                } else properties[p.Name] = "";
            }
        devices.Add(properties);
        }
    return devices.ToArray();
}

p.Valuetype 是,但有时它包含一个类似orobject的数组,我从stackoverflow中找到了部分代码,但它对我没有帮助,它说:UInt[]String[]

System.InvalidCastException:'无法将'System.UInt16 []'类型的对象转换为'System.Collections.Generic.IEnumerable`1 [System.Object]'。

我也尝试了下面的代码,但它说的是同样的事情:

int[] array = new int[] { 0, 1, 2 }; // <- I haven't access to `array` in my main problem
object obj=array;
// I only can use `obj`
// `obj` is similar to `p.Value` here
IEnumerable<object> collection = (IEnumerable<object>)obj;   // <- this line throws exception!
string output=string.join(", ",collection.Select(x=>x.ToString()));

我也试过这个代码:

var collection= p.Value as IEnumerable;
// ^ found this line from stackoverflow
// says: Using the generic type 'IEnumerable<T>' requires 1 type arguments

var collection= p.Value as IEnumerable<object>
// `collection` will be null

var collection= (object[]) p.Value
// says: Unable to cast object of type 'System.Int32[]' (or some something like String[]) to type 'System.Object[]'.

标签: c#arraysienumerableenumerable

解决方案


IEnumerable<T>是协变的,T所以这是允许的:

IEnumerable<Giraffes> giraffes = ....
var animals = (IEnumerable<Animal>)giraffes;

那么,为什么这不起作用呢?

var array = new[] { 1, 2, 3 };
var objects = (IEnumerable<object>)array; //will not compile

int延伸object,对吧?

好吧,原因是 C# 中的类型变化只允许在引用类型之间;规则是方差必须优先于标识,并且没有办法在 C# 中强制转换保留标识的值类型;只有引用类型可以并且这些类型的转换称为引用转换

var animal = (Animal)giraffe;
var o = (object)"Hello";
IFish fish = cod;
//etc.

组成对象的位不会改变,只有引用的类型会改变,因此转换的名称。请注意,在第一个示例中,animalsgiraffes是同一个对象,object.ReferenceEquals(animals, giraffes)将返回true; 我们只改变了引用它的变量的类型。

在您的情况下,IEnumerable<object>要从 an获取 an IEnumerable<someValueType>,您必须枚举并装箱每个项目,创建所需类型的新枚举。为此,您可以使用扩展方法Enumerable.Cast<T>()

IEnumerable<object> objects = array.Cast<object>();

或者自己做投影:

IEnumerable<object> objects = array.Select(i => (object)i);

推荐阅读