условная логика на основе типа - PullRequest
2 голосов
/ 06 октября 2008

Дано:

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);
       }
    }
}

Я знаю, что есть более эффективные способы проектирования этого типа взаимодействий, но из-за детали, которые могли бы объяснить это слишком долго, невозможны. Поскольку этот шаблон будет продублирован много раз, я хотел бы заменить условная логика с общей реализацией, которую я мог бы использовать только одну строку. Я не вижу простого способа реализовать этот универсальный метод / класс, но мои инстинкты говорят мне, что это возможно.

Любая помощь будет оценена.

Ответы [ 6 ]

16 голосов
/ 06 октября 2008

Я бы поместил метод в интерфейс, а затем позволил полиморфизму решить, какой метод вызвать

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.

5 голосов
/ 06 октября 2008

То, что вы хотите, это двойная отправка и шаблон посетителя в частности.

1 голос
/ 07 октября 2008
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 });
    }
}
1 голос
/ 06 октября 2008

Это немного уродливо, но оно выполняет свою работу:

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);
}

Хотя я не думаю, что сделал бы это так. На самом деле больно смотреть на это. Извините, что заставил вас всех посмотреть на это.

0 голосов
/ 06 октября 2008

Легко. В Visual Basic я делаю это все время, используя CallByName.

Sub MethodBase(value as Object)
    CallByName(Me, "RealMethod", CallType.Method, value)

Это вызовет перегрузку RealMethod, которая наиболее точно соответствует типу значения времени выполнения.

Я уверен, что вы можете использовать CallByName из C #, импортировав Microsoft.VisualBasic.Interaction или создав собственную версию, используя отражение.

0 голосов
/ 06 октября 2008

Он не существует в удобной форме с C # - см. Здесь для идеи, основанной на сопоставлении с образцом F #, которая делает именно то, что вы хотите. Вы можете сделать некоторые вещи с отражением, чтобы выбрать перегрузку во время выполнения, но это будет очень медленно и имеет серьезные проблемы, если что-либо удовлетворяет обе перегрузки. Если бы у вас было возвращаемое значение, вы могли бы использовать условный оператор;

return (I is B) ? Method((B)I) : ((I is C) ? Method((C)I) : 0);

Опять же - не красиво.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...