Дизайн класса 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.

Я считаю, что вы хотите иметь коллекцию экземпляров разных RegistrationValues-производные классы и иметь возможность повторять его и иметь разные типы для каждого элемента. Это довольно невозможно.

Вам все еще нужно привести каждый элемент к тому типу, который вам известен, потому что итерация коллекции вернет ссылки на ваш базовый тип (ParameterRegistrationValue - это указано IList параметр типа). Так что это не будет иметь никакого реального значения от перебора неуниверсальных object список.

И если вы можете безопасно выполнять это приведение для каждого параметра (вы знаете все типы), вам, вероятно, вообще не понадобится подобная коллекция - будет лучше иметь класс, который инкапсулирует все параметры в одном типе, поэтому что вы можете вызывать его со строгими типами, с IntelliSense и т. д., как это:

public class ParameterRegistration
{
  public DateTime RegistrationDate { get; set; }
  public PatientData PatientData { get; set; }
  public Guid Identifier { get; set; }
  // ...
}
Другие вопросы по тегам