Код С# для обработки разных классов с одинаковыми именами методов

Скажем, у вас есть два разных класса С# A и B, которые, хотя и не связаны с одним и тем же базовым классом, не используют одни и те же имена для методов. Например, оба класса имеют метод connect и disconnect, а также несколько других. Я хочу иметь возможность писать код один раз, который будет работать с обоими типами.

Вот упрощенный пример того, что я хотел бы сделать:

public void make_connection(Object x)
{
  x.connect() ;
  // Do some more stuff...
  x.disconnect() ;
  return ;
}

Конечно, это не компилируется, поскольку класс Object не имеет метода connect или disconnect.

Есть ли способ сделать это?

UPDATE. Я должен был сделать это ясно с самого начала: у меня есть только DLL для A и B, а не для источника.

Ответ 1

Вы можете использовать интерфейс для выполнения того, что вы хотите сделать.

interface IConnectable
{
    void Connect();

    void Disconnect();
}

Оба A и B должны реализовывать IConnectable. Затем используйте IConnectable вместо Object в качестве типа параметра для вашего метода, и все должно быть установлено.

public void MakeConnection(IConnectable connectable)
{
    connectable.Connect();

    // Do some more stuff...

    connectable.Disconnect();
}

Изменить: Поскольку у вас нет исходного кода, у вас есть несколько вариантов:

  • Используйте Max-решение с использованием ключевого слова dynamic (если вы используете .NET 4.0)
  • Используйте решение Steve с использованием методов литья и if/else
  • Создайте классы-оболочки для A и B и предложите им реализовать интерфейс (или использовать для них общий абстрактный базовый класс)

Например:

class AWrapper : IConnectable
{
    private A obj;

    public AWrapper(A obj)
    {
        this.obj = obj;
    }

    public void Connect()
    {
        this.obj.Connect();
    }

    public void Disconnect()
    {
        this.obj.Disconnect();
    }

    // other methods as necessary
}

(BWrapper будет аналогичным, просто используя B вместо A)

Затем вы можете создать обертки и передать их в MakeConnection. Это зависит от вас, как вы хотите это сделать. В зависимости от вашей ситуации один метод может быть проще, чем другие.

Ответ 2

Это будет работать в С# 4:

public void make_connection(dynamic x)
{
  x.connect() ;
  // Do some more stuff...
  x.disconnect() ;
  return ;
}

Ответ 3

Попробуйте использовать интерфейс.

Посмотрите интерфейс (ссылка на С#) и Интерфейсы (С# Руководство по программированию)

Так что-то вроде

public interface IConnections
{
    void connect();
    void disconnect();
}

public class A : IConnections
{
    public void connect()
    {
        //do something
    }

    public void disconnect()
    {
        //do something
    }
}

public class B : IConnections
{
    public void connect()
    {
        //do something
    }

    public void disconnect()
    {
        //do something
    }
}

public void make_connection(IConnections x)
{
    x.connect();
    // Do some more stuff... 
    x.disconnect();
    return;
}

Ответ 4

Существует концепция OOAD "Программа для интерфейса не для реализации" , которая позволяет избежать цепочки иерархий наследования

1- Вы можете создать interfcae

interface IConnection
{
    void Connect();
    void Disconnect();
}

2- И пусть ваши классы реализуют этот интерфейс, как показано ниже.

class A : IConnection
{
    #region IConnection Members

    public void Connect()
    {
       // your connect method implementation goes here.
    }

    public void Disconnect()
    {
        // your disconnect method implementation goes here.
    }

    #endregion
}


class B : IConnection
{
    #region IConnection Members

    public void Connect()
    {
         // your connect method implementation goes here.
    }

    public void Disconnect()
    {
        // your disconnect method implementation goes here.
    }

    #endregion
}

3 Как только вы закончили реализацию, вы можете заставить вашу функцию принять аргумент IConnection, как показано ниже.

public void makeConnection(IConnection con)
    {
        con.Connect();
        con.Disconnect();
    }

4- И из вашего кода клиента вы можете передать объект классов, который реализует интерфейс IConnect.

Ответ 5

Если решение интерфейса невозможно (например, у вас нет исходного кода), другое менее эффективное решение - использовать отражение.

Ответ 6

Как говорили другие, перераспределение использования интерфейсов или использование динамического подхода, вероятно, являются самыми элегантными способами.

Если это невозможно, вы можете применить объект к своим типам. Я бы предложил использовать as, а затем проверить, что бросок работал, непроверенный бросок был бы опасным, если бы кто-то назвал это типом, который не удалось выполнить.

например. Если типы A и B имеют метод с именем DoSomething(), тогда это будет работать...

    public static void CallDoSomething(object o)
    {
        A aObject = o as A;

        if (aObject != null)
        {
            aObject.DoSomething();
            return;
        }

        B bObject = o as B;

        if (bObject != null)
        {
            bObject.DoSomething();
            return;
        }
    }

НО это довольно уродливо, если честно... Я бы действительно попытался реорганизовать интерфейсы.

Ответ 7

Либо вам придется использовать интерфейс (или базовый класс), как показано Zach и наблюдателем, или вам придется использовать объект перед использованием:

public void make_connection(Object x) 
{ 
  ((A)x).connect() ; 
  // Do some more stuff... 
  x.disconnect() ; 
  return ; 
} 

Ответ 8

Вы также можете использовать отражение для вызова методов

Ответ 9

То, что вы хотите, называется Duck Typing.

Из Википедии:

Duck typing - это стиль динамической типизации, в котором текущий набор методов и свойств объекта определяет действительную семантику, а не ее наследование от конкретного класса или реализацию конкретного интерфейса.

С# 4.0 позволяет это, как говорили другие, использовать динамическое ключевое слово