Доступ к элементам массива (любого типа элемента) из объекта - PullRequest
0 голосов
/ 06 августа 2020

Я использую управление для доступа к свойствам устройств, и я написал ниже код для создания массива словарей. мое приложение показывает свойства в элементе управления 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 .Generi c .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[]'.

Ответы [ 2 ]

1 голос
/ 06 августа 2020

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 extends object, верно?

Ну, причина в том, что изменение типов в C# допускается только между ссылочными типами ; правило состоит в том, что дисперсия должна препятствовать идентичности, и в C # невозможно привести тип значения, сохраняющий идентичность; могут использоваться только ссылочные типы, и эти типы преобразования называются ссылочными преобразованиями :

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

Биты, составляющие объект не изменяются , только тип Ссылка меняется, отсюда и название преобразования. Обратите внимание, что в самом первом примере animals и giraffes - это один и тот же объект, object.ReferenceEquals(animals, giraffes) вернет true; мы изменили только тип ссылающейся на него переменной.

В вашем случае, чтобы получить IEnumerable<object> из IEnumerable<someValueType>, вам нужно будет перечислить и поместить в коробку каждый элемент , создавая новый перечислимый желаемого типа. Для этого вы можете использовать метод расширения Enumerable.Cast<T>():

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

Или сделать проекцию самостоятельно:

IEnumerable<object> objects = array.Select(i => (object)i);
0 голосов
/ 07 августа 2020

второй код:

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();
}
...