【问题标题】:Accessing elements of an Array (of any element type) from an object从对象访问 Array(任何元素类型)的元素
【发布时间】:2020-11-26 13:01:58
【问题描述】:

我使用管理来访问设备属性,并在下面编写了一个代码来创建一个字典数组。我的应用程序在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.Value 类型是object,但有时它包含像UInt[]String[] 这样的数组,我从stackoverflow 找到了部分代码,但它没有帮助我,它说:

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# arrays ienumerable enumerable


    【解决方案1】:

    第二个代码:

    int[] array = new int[] { 0, 1, 2 };
    object obj=array;
    var obj_array=(Array)obj;
    IEnumerable<object> collection = obj_array.Cast<object>();
    string output=string.join(", ",collection.Select(x=>x.ToString()));
    

    所以主要代码是:

    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) {
                            var array = (Array)p.Value;
                            var collection = array.Cast<object>();
                            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();
    }
    

    【讨论】:

      【解决方案2】:

      IEnumerable&lt;T&gt;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&lt;someValueType&gt; 获得 IEnumerable&lt;object&gt;,您必须枚举并装箱每个项目创建所需类型的新可枚举。为此,您可以使用扩展方法Enumerable.Cast&lt;T&gt;()

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

      或者自己做投影:

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

      【讨论】:

      • 感谢您的回答,但第二个代码不是我的主要问题。我的主要问题是第一个代码,我无法访问array 我只能在object 类型中使用p.Value
      猜你喜欢
      • 1970-01-01
      • 2018-02-17
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-28
      • 2013-06-22
      相关资源
      最近更新 更多