从对象访问数组(任何元素类型)的元素
Accessing elements of an Array (of any element type) from an object
我使用管理来访问设备属性,并在下面编写了一段代码来创建一个字典数组。我的应用程序在 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[]
,我从 Whosebug 中找到了部分代码,但它没有'帮助我,它说:
System.InvalidCastException: 'Unable to cast object of type 'System.UInt16[]' to type '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 Whosebug
// 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[]'.
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# 中的类型差异只允许在 引用类型 之间;规则是 variance 必须与 identity 相反,并且在 C# 中无法强制转换保留 identity 的值类型;只有引用类型可以,这些类型的转换称为 引用转换:
var animal = (Animal)giraffe;
var o = (object)"Hello";
IFish fish = cod;
//etc.
组成对象的位没有改变,只有引用的类型改变了,因此转换的名称也改变了。请注意,在第一个示例中,animals
和 giraffes
是同一个对象,object.ReferenceEquals(animals, giraffes)
将 return true
;我们只更改了引用它的变量的类型。
在您的情况下,要从 IEnumerable<someValueType>
中获得 IEnumerable<object>
,您必须枚举并装箱每个项目 创建一个新的可枚举所需的类型。为此,您可以使用扩展方法 Enumerable.Cast<T>()
:
IEnumerable<object> objects = array.Cast<object>();
或者自己做投影:
IEnumerable<object> objects = array.Select(i => (object)i);
第二个密码:
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();
}
我使用管理来访问设备属性,并在下面编写了一段代码来创建一个字典数组。我的应用程序在 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[]
,我从 Whosebug 中找到了部分代码,但它没有'帮助我,它说:
System.InvalidCastException: 'Unable to cast object of type 'System.UInt16[]' to type '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 Whosebug
// 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[]'.
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# 中的类型差异只允许在 引用类型 之间;规则是 variance 必须与 identity 相反,并且在 C# 中无法强制转换保留 identity 的值类型;只有引用类型可以,这些类型的转换称为 引用转换:
var animal = (Animal)giraffe;
var o = (object)"Hello";
IFish fish = cod;
//etc.
组成对象的位没有改变,只有引用的类型改变了,因此转换的名称也改变了。请注意,在第一个示例中,animals
和 giraffes
是同一个对象,object.ReferenceEquals(animals, giraffes)
将 return true
;我们只更改了引用它的变量的类型。
在您的情况下,要从 IEnumerable<someValueType>
中获得 IEnumerable<object>
,您必须枚举并装箱每个项目 创建一个新的可枚举所需的类型。为此,您可以使用扩展方法 Enumerable.Cast<T>()
:
IEnumerable<object> objects = array.Cast<object>();
或者自己做投影:
IEnumerable<object> objects = array.Select(i => (object)i);
第二个密码:
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();
}