Как правильно реализовать передачу параметров в конструктор?
Вопрос состоит в следующем: имеем базовый класс с некими параметрами, который реализует интерфейс IOptions:
public interface IOptions
{
int Fdis { get; set; }
}
public class BaseOptions : IOptions
{
public int Fdis { get; set; }
}
Имеется ряд приборов, которые наследуют базовые настройки и добавляют свои уникальные свойства:
public class PhotoDeviceOptions : BaseOptions
{
public int LightLevel { get; set; }
public int LightColor { get; set; }
}
public class PhohoDeviceOptions : BaseOptions
{
public bool NoiseMasking { get; set; }
public int SoundWaveType { get; set; }
}
И также существует два класса, который используют эти настройки:
public interface IDeviceProcessor
{
void Process();
}
public class PhotoDeviceProcessor : IDeviceProcessor
{
public void Process()
{
// здесь нужно использовать PhotoDeviceOptions
photoDevice.UpdateLightSettings();
}
}
public class PhonoDeviceProcessor : IDeviceProcessor
{
public void Process()
{
// здесь нужно использовать PhonoDeviceOptions
phonoDevice.UpdateSoundSettings();
}
}
Как правильно реализовать передачу настроек в DeviceProcessor ? Мне в голову приходят только два варианта:
Передавать интерфейс IOptions и затем преобразовывать его в нужный тип:
private PhotoDeviceOptions _options; public PhotoDeviceProcessor (IOptions options) { if(options is not PhotoDeviceOptions) throw new InvalidCastException(nameof(options)); _options = options as PhotoDeviceOptions; }Передавать тип настроек, соответствующих классу:
private PhotoDeviceOptions _options; public PhotoDeviceProcessor (PhotoDeviceOptions options) { _options = options; }
Или есть более правильный способ реализации?
Ответы (1 шт):
Написал ответ до того как вы обновили пример, поэтому ответ будет абстрактный. :)
У вас есть несколько конкретных моделей данных, здесь будет пример одной, потому что для контраста я буду использовать примитивный тип в качестве второй.
public class MathArguments
{
public double A { get; set; }
public double B { get; set; }
}
У них нет общих интерфейсов, вообще ничего общего. Но могут быть и общие базовые типы, это не запрещается.
И есть вот такие интерфейсы.
public interface ICalculator
{
double Calculate();
}
public interface ICalculator<T> : ICalculator
{
T Args { get; }
}
И вот здесь начинается интересное.
Давайте к примеру посчитаем вот такое
Math.Sqrt(A + B);
С помощью моделей данных и абстракций.
Реализуем 2 раза интерфейс.
public class SumCalculator : ICalculator<MathArguments>
{
public MathArguments Args { get; }
public SumCalculator(MathArguments args)
{
Args = args;
}
public double Calculate()
{
return Args.A + Args.B;
}
}
public class SqrtCalculator : ICalculator<double>
{
public double Args { get; }
public SqrtCalculator(double args)
{
Args = args;
}
public double Calculate()
{
return Math.Sqrt(Args);
}
}
private static void Main(string[] args)
{
var arguments = new MathArguments { A = 2, B = 2 };
ICalculator sumCalc = new SumCalculator(arguments);
double sum = sumCalc.Calculate();
ICalculator sqrtCalc = new SqrtCalculator(sum);
double result = sqrtCalc.Calculate();
Console.WriteLine(result); // 2
Console.ReadKey();
}
Быть может пример не совсем хороший, но подходит под ваши требования. Смысл примера в том, что можно использовать обычный интерфейс для вызова метода, например из коллекции классов этого типа. И обобщенный интерфейс, чтобы не было ошибок в реализации или был возможен проброс типа через другие обобщения.
К сожалению обобщений для конструкторов не существует, поэтому правильная реализация конструктора - на совести разработчика. Свойство { get; } как бы намекает, что его можно задать только в конструкторе. Если вам не нужно публичное свойство, то и интерфейс с обобщением не потребуется.
Отсюда делаю вывод, что вариант Передавать тип настроек, соответствующих классу: более правильный.