Дизайн класса C# с общей структурой
Это может быть просто, но моя голова отказывается оборачиваться вокруг этого, поэтому внешний вид всегда полезен в этом случае!
Мне нужно спроектировать иерархию объектов для реализации регистрации параметров для пациента. Это произойдет в определенный день и соберет ряд различных параметров о пациенте (артериальное давление, сердечный ритм и т. Д.). Значения этих регистраций параметров могут быть разных типов, таких как строки, целые числа, числа с плавающей запятой или даже направляющие (для списков поиска).
Итак, мы имеем:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public IList<ParameterRegistrationValue> ParameterRegistrationValues { get; set; }
}
public class ParameterRegistrationValue
{
public Parameter Parameter { get; set; }
public RegistrationValue RegistrationValue { get; set; } // this needs to accomodate the different possible types of registrations!
}
public class Parameter
{
// some general information about Parameters
}
public class RegistrationValue<T>
{
public RegistrationValue(T value)
{
Value = value;
}
public T Value { get; private set; }
}
ОБНОВЛЕНИЕ: Благодаря предложениям модель теперь трансформировалась в следующее:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public IList<ParameterRegistrationValue> ParameterRegistrationValues { get; set; }
}
public abstract class ParameterRegistrationValue()
{
public static ParameterRegistrationValue CreateParameterRegistrationValue(ParameterType type)
{
switch(type)
{
case ParameterType.Integer:
return new ParameterRegistrationValue<Int32>();
case ParameterType.String:
return new ParameterRegistrationValue<String>();
case ParameterType.Guid:
return new ParameterRegistrationValue<Guid>();
default: throw new ArgumentOutOfRangeException("Invalid ParameterType: " + type);
}
}
public Parameter Parameter { get; set; }
}
public class ParameterRegistrationValue<T> : ParameterRegistrationValue
{
public T RegistrationValue {get; set; }
}
public enum ParameterType
{
Integer,
Guid,
String
}
public class Parameter
{
public string ParameterName { get; set; }
public ParameterType ParameterType { get; set;}
}
что действительно немного проще, но теперь мне интересно, так как IList в Parameter Registration указывает на абстрактный объект ParameterRegistrationValue, как я смогу получить фактическое значение (так как оно хранится в подобъектах)?
Может быть, в общем и целом, это не совсем то, что нужно:
4 ответа
Если вы не знаете окончательный набор параметров и соответствующий тип каждого параметра, тогда, вероятно, обобщенные значения не помогут - используйте объект как тип значения параметра.
Кроме того, перебор списка параметров будет проблематичным, так как вам придется изучить тип каждого элемента, чтобы определить, как обрабатывать значение.
Что вы пытаетесь достичь с помощью дженериков? Да, они классные (и, вероятно, не лучшая идея для бокса / распаковки), но в некоторых случаях вы можете использовать объект (для простоты и гибкости).
- Павел
То, что вы могли бы представить, это абстрактный базовый класс для RegistrationValue<T>
это не является общим, так что ваш ParameterRegistrationValue
Класс может содержать неуниверсальную ссылку, не требуя знания типа. В качестве альтернативы может быть целесообразно ParameterRegistrationValue
также и добавьте для него неуниверсальный базовый класс (чтобы список значений в ParameterRegistration
могут быть разных типов.
1-й способ:
public abstract class RegistrationValue
{
}
public class RegistrationValue<T> : RegistrationValue
{
public RegistrationValue(T value)
{
Value = value;
}
public T Value { get; private set; }
}
И теперь ваш код должен скомпилироваться.
Если у вас есть неуниверсальный базовый класс, я бы также переместил в этот базовый класс любые члены универсального класса, которые не зависят от параметров универсального типа. В этом примере их нет, но если бы мы вместо этого модифицировали ParameterRegistrationValue
чтобы быть общим, я бы переехал Parameter
в неуниверсальный базовый класс (потому что он не зависит от параметра типа для RegistrationValue
)
Возможно, вам следует использовать public RegistrationValue RegistrationValue, где T - тип, использующий в общем. Например, T - это String или другой класс или структура.
Или вы должны сделать класс ParameterRegistrationValue как универсальный, чтобы использовать универсальный аргумент в поле RegistrationValue.
Я считаю, что вы хотите иметь коллекцию экземпляров разных RegistrationValue
s-производные классы и иметь возможность повторять его и иметь разные типы для каждого элемента. Это довольно невозможно.
Вам все еще нужно привести каждый элемент к тому типу, который вам известен, потому что итерация коллекции вернет ссылки на ваш базовый тип (ParameterRegistrationValue
- это указано IList
параметр типа). Так что это не будет иметь никакого реального значения от перебора неуниверсальных object
список.
И если вы можете безопасно выполнять это приведение для каждого параметра (вы знаете все типы), вам, вероятно, вообще не понадобится подобная коллекция - будет лучше иметь класс, который инкапсулирует все параметры в одном типе, поэтому что вы можете вызывать его со строгими типами, с IntelliSense и т. д., как это:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public PatientData PatientData { get; set; }
public Guid Identifier { get; set; }
// ...
}