#c# #polymorphism
#c# #полиморфизм
Вопрос:
Классы, приведенные ниже, состоят из
A — класс отца
B — дочерний класс
Держатель — Содержит список A
Я хочу получить доступ к дочернему свойству из списка объектов-отцов. Почему я не могу этого сделать? Или лучший вопрос, как мне это сделать?
public class A
{
public int var = 0;
}
public class B : A
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public B()
{
}
public B(B p_B)
{
Property1 = p_B.Property1;
Property2 = p_B.Property2;
}
}
class Holder
{
private List<A> m_Objects = new List<A>();
public void AddObject(A p_Object)
{
m_Objects.Add(p_Object);
}
public void AddObjectProperty1(B p_B)
{
// At this point, m_Objects holds a B-object. And I want to add the value from Property1
// but there is no Property1 in the A-class so I cant do this. How do I use the base.values from
// a statement like the one below?
int index = m_Objects.FindIndex(item => item.Property1 == p_B.Property1);
if (index > -1)
m_Objects.ElementAt(index).Property1 = p_B.Property1;
}
}
class Program
{
static void Main(string[] args)
{
// Class to hold the objects
Holder h = new Holder();
// Create a B object
B b = new B();
b.Property1 = 1;
b.Property2 = 2;
// Place a new instance of the B-object in a list of A's
h.AddObject(new B(b));
// Add the value from Property1 to the value in the b-object in the a-list. :P
h.AddObjectProperty1(b);
Console.WriteLine( b.var);
Console.ReadLine();
}
}
Комментарии:
1. Не называйте свою переменную
var
. Во-первых, это ничего не значит, во-вторых,var
это также ключевое слово в C # — ваш код станет беспорядочным и сложным в обслуживании.2. Да, спасибо за ваш совет! 🙂 Я обычно не называю переменные var, я просто пытался создать что-то максимально общее в этом конкретном случае! Но спасибо, что заметили это!
3. Почему вопрос отклонен? 🙁
Ответ №1:
Вы можете использовать приведение типов:
(m_Objects[i] as B).Property1
Или
((B)m_Objects[i]).Property1
Комментарии:
1. Я за тебя отвечаю! Я попробовал это решение, но свойство 1 не распознается, даже если приведение типов правильное. 🙁
2. Что значит: не распознано. Он не компилируется или не завершается с ошибкой, или вы получаете нулевое значение?
Ответ №2:
Во время компиляции у компилятора нет возможности узнать, вы бы только добавили B
s в свой список A
s. Таким образом, нет никакой гарантии, что каждый item
из следующих запросов является экземпляром B
и, следовательно, имеет Property1
int index = m_Objects.FindIndex(item => item.Property1 == p_B.Property1);
Первая возможность — это приведение, как в ответе Артема. Но это не удастся, если вы не все элементы в списке действительно B
s. Итак, если вы полагаетесь на все элементы в m_Objects
, чтобы быть экземплярами B
, почему бы вам просто не использовать List<B> m_Objects
?
Если вам нужен смешанный список, вы должны выполнить проверку типа в запросе, чтобы убедиться, что вы имеете дело с экземпляром B
перед приведением.
int index = m_Objects.FindIndex(item => (item is B) amp;amp; (item as B).Property1 == p_B.Property1);
Смотрите этот пример DotNetFiddle
Комментарии:
1. Это именно то, что я искал. Причина, по которой я хочу хранить B в A, а не наоборот, заключается в том, что я хочу использовать полиморфизм для хранения объектов таким образом, который я нахожу разумным (что может быть не так). Например, если holderclass является кошельком. Я хочу хранить наличные деньги (читается как A), которые могут быть в виде монет или банкнот (B или C, если C существует). Звучит это хорошо для меня, так как я могу просто иметь список наличных денег. Я попробовал ваше решение, и синтаксис был правильным, однако свойство 1 не найдено при приведении элемента: (Есть какие-нибудь подсказки? Я думаю об этом неправильно?
2. С этой точки зрения использование a
List<A>
имеет смысл. Что вы подразумеваете под «Property1 не найден»? Смотрите обновленную скрипку . Кажется, работает так, как ожидалось.