Можно ли написать такую конструкцию через Паттерн матчинг реализовать?
Идея что по свойству надо создать нужный тип объекта из иерархии и вызвать специфический метод для данного типа
public Shape CreateShape(string name, int area)
{
Shape = switch
{
"circle" => {
var circle = new Circle(area);
circle.CalculateSomethingSpecialForCircle();
return circle;
},
"square" => {
var square= new Square(area);
square.CalculateSomethingSpecialForSquare();
return square;
}
}
}
Здравствуйте, snaphold, Вы писали:
S>Можно ли написать такую конструкцию через Паттерн матчинг реализовать? S>Идея что по свойству надо создать нужный тип объекта из иерархии и вызвать специфический метод для данного типа S> circle.CalculateSomethingSpecialForCircle();
Паттерн-матчинг тут вообще не причём, тут рефлексия нужна. Как вариант (если это возможно), назвать "специфический метод" у всех одинаково и тупо перегрузить! Классическое применение virtual.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, snaphold, Вы писали:
S>>Можно ли написать такую конструкцию через Паттерн матчинг реализовать?
НС>Можно. В чем проблема?
не пойму как написать такое?
с методом если что можно как выше посоветовали с виртуальным. но общая идея что тип создаваемый определяется по некому свойству
B>Паттерн-матчинг тут вообще не причём, тут рефлексия нужна. Как вариант (если это возможно), назвать "специфический метод" у всех одинаково и тупо перегрузить! Классическое применение virtual.
Здравствуйте, Baiker, Вы писали:
B>Паттерн-матчинг тут вообще не причём, тут рефлексия нужна. Как вариант (если это возможно), назвать "специфический метод" у всех одинаково и тупо перегрузить! Классическое применение virtual.
Именно. Вызов разных методов в зависимости от типа — это как раз то, для чего нужен virtual.
Что касается создания объектов, создать объект можно только точно зная его тип, иначе не получится. Нужно только выбрать и изолировать точку в приложении, где это знание будет храниться. Весь смысл в том, чтобы такая точка была одна, чтобы не плодить switch/case по всему коду.
Например, можно зарегистрировать нужные типы, при этом все они должны быть производные от базового класса/интерфейса.
Dictionary<string, Type> registry = new();
// один раз при запуске программы
registry.Add("circle", typeof(Circle));
registry.Add("square", typeof(Square));
// затем в вашем методеpublic Shape CreateShape(string name, int area)
{
var type = registry[name];
var shape = (Shape)Activator.CreateInstance(type);
shape.CalculateSomethingSpecial(); // это базовый виртуальный метод. вызовется на соответствующем классе.
}
Остаётся только дописывать классы, производные от абстрактного Shape и не забывать регистрировать их.
Можно пойти чуть дальше и цеплять информацию об имени прямо на эти классы, например, при помощи атрибутов, а потом автоматически находить все такие классы и регистрировать их. Собственно, так устроена библиотека MEF (https://learn.microsoft.com/ru-ru/dotnet/framework/mef/). Для Net Core тоже есть аналог или порт.
Здравствуйте, snaphold, Вы писали:
S>Можно ли написать такую конструкцию через Паттерн матчинг реализовать? S>Идея что по свойству надо создать нужный тип объекта из иерархии и вызвать специфический метод для данного типа
S>
S>public Shape CreateShape(string name, int area)
S>{
S> Shape = switch
S> {
S> "circle" => {
S> var circle = new Circle(area);
S> circle.CalculateSomethingSpecialForCircle();
S> return circle;
S> },
S> "square" => {
S> var square= new Square(area);
S> square.CalculateSomethingSpecialForSquare();
S> return square;
S> }
S> }
S>}
S>
Ну вы в принципе практически рабочий код написали.
public Shape CreateShape(string name, int area)
{
switch(name)
{
case"circle":
var circle = new Circle(area);
circle.CalculateSomethingSpecialForCircle();
return circle;
case"square":
var square= new Square(area);
square.CalculateSomethingSpecialForSquare();
return square;
}
}
В чём подвох?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, snaphold, Вы писали:
S>Можно ли написать такую конструкцию через Паттерн матчинг реализовать? S>Идея что по свойству надо создать нужный тип объекта из иерархии и вызвать специфический метод для данного типа
S>
S>public Shape CreateShape(string name, int area)
S>{
S> Shape = switch
S> {
S> "circle" => {
S> var circle = new Circle(area);
S> circle.CalculateSomethingSpecialForCircle();
S> return circle;
S> },
S> "square" => {
S> var square= new Square(area);
S> square.CalculateSomethingSpecialForSquare();
S> return square;
S> }
S> }
S>}
S>
Если непременно чешется использовать switch expression, а не switch statement, то можно так:
public static class Hacks
{
public static T Apply(this T object, Action<T> action)
{
action(object);
return object;
}
}
...
public Shape CreateShape(string name, int area) =>
name switch
{
"circle" => (new Circle(area)).Apply(c=>c.CalculateSomethingSpecialForCircle()),
"square" => (new Square(area)).Apply(s=>s.CalculateSomethingSpecialForSquare()),
_ => throw new ArgumentException("name");
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>с методом если что можно как выше посоветовали с виртуальным. но общая идея что тип создаваемый определяется по некому свойству
Я по прежнему не понимаю в чем ты видишь проблему. Твой пример не компилируется только потому что синтаксис switch expression не позволяет statements. Переход на switch statement либо вынос стейтментов в отдельный метод (можно локальный) эту проблему решает.
но это вроде не паттерн матчинг когда кейс есть, а простой свитч кейс. хотел понять можно ли вынести объявление Shape за пределы свитча и убрать явные кейсы.
то есть чтобы результат свитча сразу присвоился Shape
Здравствуйте, snaphold, Вы писали: S>но это вроде не паттерн матчинг когда кейс есть, а простой свитч кейс. хотел понять можно ли вынести объявление Shape за пределы свитча и убрать явные кейсы.
Строгое определение паттерн матчинга приведено в первоисточнике: https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching
switch там не обязателен. S>то есть чтобы результат свитча сразу присвоился Shape
В вашем примере, Shape — это тип. Ему ничего присвоить нельзя. И по логике вашего кода вы собственно пытаетесь вернуть фигуру из метода, а не присваивать её в какую-либо переменную (да и зачем?).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.