Работа с object[] и List object

253
28 сентября 2021, 20:20
List<object> list = new List<object>();
list.Add(new object[]
{
     Convert.ToByte(1),  
     Convert.ToInt32(100), 
     Convert.ToString("test") 
});

Я добавляю object[] в List object. Как я могу удалить этот object[]?

list.Remove(new object[]
{
    Convert.ToByte(1),  
    Convert.ToInt32(100), 
    Convert.ToString("test") 
}); //Это не работает

И как я могу получить значения из List object -> object[] -> к примеру значение строки (я изначально записал строку "test")

Answer 1

В C# object является ссылочным типом, это значит, что при создание чего либо через new - вы получаете новый объект, с ссылкой которого вы дальше и взаимодействуете.

Написав

list.Add(new object[]
{
     Convert.ToByte(1),  
     Convert.ToInt32(100), 
     Convert.ToString("test") 
});

вы создаете новый объект object[], ссылка на который записывается в List<T>.

Когда вы делаете

list.Remove(new object[]
{
    Convert.ToByte(1),  
    Convert.ToInt32(100), 
    Convert.ToString("test") 
});

у вас естественно это не будет работать, так как вы создаете совершенно новый объект, ссылка которого не будет равна той, что у вас в коллекции.

Для удаления объекта из коллекции, нам нужен его индекс, либо его ссылка, получить ссылку мы можем многими способами, хоть var item = list[0];, я например возьму LINQ и с его помощи удалю объект, внутри которого есть текст test:

var searchItem = list.Where(x=>x is object[]).FirstOrDefault(x => ((object[])x).Contains("test"));

В результате у нас будет либо NULL, либо нужная нам ссылка на объект из коллекции, который мы потом смело сможем удалить при помощи Remove().

Что касается получения значений, то я думаю вы тут сами со своими костылями разберетесь, все необходимое я вроде вас уже дал. Ну а вообще, советую использовать что то, что менее динамично что ли, так вы сами себе палки в колеса ставите и делаете лишнюю работу.

Answer 2

Не нужно работать с object и массивами такого типа.

Давайте я немного распишу то, о чём говорилось в комментариях.

Допустим, имеется класс

class CakeSet
{
    public int Id { get; set; }
    public string Value { get; set; }
}

Попробуем использовать его:

var cakes = new List<CakeSet>();
cakes.Add(new CakeSet { Id = 1, Value = "test" });
cakes.Remove(new CakeSet { Id = 1, Value = "test" });
Console.WriteLine(cakes.Count); // выведет 1

Мы добавили в список экземпляр нашего класса и попробовали удалить другой экземпляр с такими же значениями свойств. Но удаления не произошло. Почему? Потому что это другой экземпляр ссылочного типа. Их ссылки не равны - они разные.

Что можно сделать. Можно реализовать в этом классе методы Equals и GetHashCode таким образом, что сравнение экземпляров будет происходить не по ссылкам, а на основе значений свойств. Например, так (код автосгенерирован):

class CakeSet
{
    public int Id { get; set; }
    public string Value { get; set; }
    public bool Equals(CakeSet other) =>
        Id == other.Id && string.Equals(Value, other.Value);
    public override bool Equals(object obj) =>
        obj is CakeSet other && Equals(other);
    public override int GetHashCode()
    {
        unchecked
        {
            return (Id * 397) ^ (Value != null ? Value.GetHashCode() : 0);
        }
    }
}

Теперь вышеприведённый код сработает - удаление из списка произойдёт.

Другой способ - использование структуры (значимого типа) вместо класса.

struct CakeSet
{
    public int Id { get; set; }
    public string Value { get; set; }
}

Просто меняем в определении типа ключевое слово class на struct и готово. Заманчиво? Да, но не спешите так делать. Применение структур чревато многими проблемами. Если вы пока не знаете, как правильно работать со значимыми типами, то лучше не используйте их.

Другой способ, о котором тоже писали в комментариях: использование кортежей (tuple).
Это удобно тем, что не нужно создавать класс.

var list = new List<Tuple<byte, int, string>>();
list.Add(Tuple.Create((byte)1, 100, "test"));
list.Remove(Tuple.Create((byte)1, 100, "test"));
Console.WriteLine(list.Count); // 0

Тип кортежа определяется на лету. При этом он обеспечивает строгую типизацию (из-за этого единичку приходится кастить к байту).

Компилятор автоматически генерирует методы сравнения (которые мы выше самостоятельно создавали для класса) для кортежей по всем полям.

Ну и напоследок, кортежи значимого типа: ValueTuple.

var list = new List<(byte, int, string)>();
list.Add((1, 100, "test"));
list.Remove((1, 100, "test"));
Console.WriteLine(list.Count); // 0

Синтаксис ещё проще. Но, опять же, нужно знать их устройство под капотом, чтобы использовать правильно и без ошибок.

В одном коротком сообщении все нюансы не описать. Читайте документацию по структурам и кортежам прежде чем их использовать.

READ ALSO
C# асинхронная загрузка файла

C# асинхронная загрузка файла

Целиком задача заключается в загрузке трех картинок для трех PictureBoxПо условию задачи пользователь может загружать их в любой момент, поэтому...

91
C# перенос кода в функцию [закрыт]

C# перенос кода в функцию [закрыт]

Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение

299
Незапускается поиск Bluetooth устройств

Незапускается поиск Bluetooth устройств

Пишу кроссплатформенную реализацию поиска BLE устройствИмею следующий код обертки над стандартным UWP классом:

150