Я пытаюсь создать диспетчер сцены или штата, который хранит словарь для каждого состояния в качестве способа загрузки или изменения состояния программы (например, состояние главного меню и Состояние игры). У меня есть куча производных классов базового класса State, которые имеют переменные, которые не включены в базовый класс State. Могу ли я безопасно хранить их в этом словаре? Будет ли у меня потеря данных? Если это не сработает, каковы альтернативные методы для достижения моей цели?Хранение производных классов в базовом классе Словарь
ответ
Это похоже на то, что вы можете легко проверить себя. Но только для удовольствия, что у вас есть базовый класс, как:
public class Base
{
public string Name
{
get;
set;
}
public override string ToString()
{
return Name;
}
}
и производный класс, как:
public class Derived : Base
{
public string Description
{
get;
set;
}
public override string ToString()
{
return base.ToString() + " - " + Description;
}
}
Затем вы можете создать настройку, как это:
Base baseObject = new Base{ Name = "Base"};
Derived derivedObject = new Derived { Name = "Derived", Description = "Description" };
Dictionary<int, Base> dictionary = new Dictionary<int, Base>();
dictionary.Add(1, baseObject);
dictionary.Add(2, derivedObject);
Теперь вы можете запустить небольшой тест, чтобы увидеть, если какая-либо информация будет потеряна:
foreach (Base value in dictionary.Values)
{
Console.WriteLine(value.ToString());
}
Как вы можете видеть, вызывается не только правильный переопределенный ToString()
, но также он имеет правильное значение для свойства Description
. Так что нет, вы ничего не «теряете». Но до тех пор, пока это тип base
, вы можете получить доступ только к объектам base
.
КПП. Вы также можете проверить, если значение действительно is
определенный производный тип:
foreach (Base value in dictionary.Values)
{
if (value is Derived)
{
Console.WriteLine("{0} is Derived", value.Name);
// trying to access value.Description at this point
// would cause a compiler error "Cannot resolve symbol".
}
else
{
Console.WriteLine("{0} is not Derived", value.Name);
}
}
И as
и чек на нуль, вы можете «безопасно» (т.е. без исключения, вызванного прямым литьем, например) получить значение в «полный» производственный тип, где снова можно получить доступ ко всем дополнительным свойствам:
foreach (Base value in dictionary.Values)
{
Derived derived = value as Derived;
if (derived != null)
{
Console.WriteLine("{0} is Derived and has Description: {1}",
derived.Name, derived.Description);
// now that derived actually is of type Derived,
// accessing derived.Description is perfectly fine.
}
}