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")
В 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()
.
Что касается получения значений, то я думаю вы тут сами со своими костылями разберетесь, все необходимое я вроде вас уже дал. Ну а вообще, советую использовать что то, что менее динамично что ли, так вы сами себе палки в колеса ставите и делаете лишнюю работу.
Не нужно работать с 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
Синтаксис ещё проще. Но, опять же, нужно знать их устройство под капотом, чтобы использовать правильно и без ошибок.
В одном коротком сообщении все нюансы не описать. Читайте документацию по структурам и кортежам прежде чем их использовать.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Целиком задача заключается в загрузке трех картинок для трех PictureBoxПо условию задачи пользователь может загружать их в любой момент, поэтому...
Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение
Пишу кроссплатформенную реализацию поиска BLE устройствИмею следующий код обертки над стандартным UWP классом: