Код С# для обработки разных классов с одинаковыми именами методов
Скажем, у вас есть два разных класса С# 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 позволяет это, как говорили другие, использовать динамическое ключевое слово