условная логика, основанная на типе
-
05-07-2019 - |
Вопрос
Данный:
interface I
{
}
class B: I
{
}
class C: I
{
}
class A
{
public void Method(B arg)
{
}
public void Method(C arg)
{
}
public void Method(I arg)
{
// THIS is the method I want to simplify.
if (I is B)
{
this.Method(arg as B);
}
else if (I is C)
{
this.Method(arg as C);
}
}
}
Я знаю, что есть лучшие способы разработки этого типа взаимодействий, но из -за деталей, которые займет слишком много времени, чтобы объяснить это невозможно.Поскольку этот шаблон будет продублирован много раз, я хотел бы заменить условную логику на общую реализацию, которую я мог бы использовать только одну строку.Я не вижу простого способа реализовать этот общий метод/класс, но мои инстинкты подсказывают мне, что это возможно.
Любая помощь будет оценена по достоинству.
Решение
То, что вы хотите, это двойная отправка, и шаблон посетителя в частности.
Другие советы
Я бы поместил метод внутри интерфейса, а затем позволил полиморфизму решить, какой метод вызывать.
interface I
{
void Method();
}
class B : I
{
public void Method() { /* previously A.Method(B) */}
}
class C : I
{
public void Method() { /* previously A.Method(C) */ }
}
class A
{
public void Method(I obj)
{
obj.Method();
}
}
Теперь, когда вам нужно добавить новый класс, вам нужно всего лишь реализовать I.Method.Вам не нужно прикасаться к A.Method.
Это довольно уродливо, но оно выполняет свою работу:
public void Method(B arg)
{
if (arg == null) return;
...
}
public void Method(C arg)
{
if (arg == null) return;
...
}
public void Method(I arg)
{
this.Method(arg as B);
this.Method(arg as C);
}
Хотя я не думаю, что поступил бы таким образом.На самом деле больно смотреть на это.Мне жаль, что я заставил вас всех посмотреть на это.
interface I
{
}
class B : I
{
}
class C : I
{
}
class A
{
public void Method(B arg)
{
Console.WriteLine("I'm in B");
}
public void Method(C arg)
{
Console.WriteLine("I'm in C");
}
public void Method(I arg)
{
Type type = arg.GetType();
MethodInfo method = typeof(A).GetMethod("Method", new Type[] { type });
method.Invoke(this, new I[] { arg });
}
}
В C# его не существует в удобной форме - глянь сюда идея, основанная на сопоставлении шаблонов F#, делает именно то, что вы хотите.Вы можете сделать некоторые вещи с помощью отражения, чтобы выбрать перегрузку во время выполнения, но это будет очень медленно и приведет к серьезным проблемам, если что-то будет удовлетворять обеим перегрузкам.Если бы у вас было возвращаемое значение, вы могли бы использовать условный оператор;
return (I is B) ? Method((B)I) : ((I is C) ? Method((C)I) : 0);
Опять же – некрасиво.
Легкий.В Visual Basic я все время делаю это, используя CallByName.
Sub MethodBase(value as Object)
CallByName(Me, "RealMethod", CallType.Method, value)
Это вызовет перегрузку RealMethod, которая наиболее точно соответствует типу значения времени выполнения.
Я уверен, что вы можете использовать CallByName из C#, импортировав Microsoft.VisualBasic.Interaction или создав свою собственную версию с использованием отражения.