Способ расширить существующий класс без создания нового класса в C#
У меня есть хороший полный класс, который делает классные вещи. Мне нужно разрешить пользователям использовать этот класс, заменив в нем некоторые методы, но наследование не допускается, поскольку этот класс также используется в других классах приложений.
Это похоже на то, что у вас есть класс, который создает таблицу, но вам нужно разрешить пользователям переопределять метод, который создает ячейку таблицы, чтобы пользователь мог напечатать что-то нестандартное в этой ячейке. Класс, однако, имеет способ печати содержимого ячейки по умолчанию (в случае, если пользователю не нужно настраивать его).
Есть ли какой-либо общепринятый или стандартизированный способ добиться этого?
3 ответа
обновленный
Имея "галерею арахиса", отметьте, что мой подход (внизу) не будет соответствовать требованиям, вот другой способ:
Используйте делегирование. Определите определенные общедоступные свойства с помощью типа Action или Func. Там, где в вашем коде нужно вызывать эти поведения, сравните свойства со значением NULL. Если ноль, используйте ваше поведение по умолчанию. Если нет, вызовите значения.
Ваш код вызова МОЖЕТ установить свойства, но не обязан.
(первая попытка) Альтернативные подходы:
Вы описываете метод расширения или использование наследования, если оно доступно.
Методы расширения позволяют вам "добавлять" методы к существующим типам, не создавая новый производный тип, не перекомпилируя или иным образом не изменяя исходный тип. Методы расширения представляют собой особый вид статического метода, но они вызываются так, как если бы они были методами экземпляра в расширенном типе. Для клиентского кода, написанного на C# и Visual Basic, нет очевидной разницы между вызовом метода расширения и методами, которые фактически определены в типе.
https://msdn.microsoft.com/en-us//library/bb383977.aspx
Наследование, наряду с инкапсуляцией и полиморфизмом, является одной из трех основных характеристик (или столпов) объектно-ориентированного программирования. Наследование позволяет создавать новые классы, которые повторно используют, расширяют и изменяют поведение, определенное в других классах. Класс, члены которого наследуются, называется базовым классом, а класс, который наследует эти члены, называется производным классом. Производный класс может иметь только один прямой базовый класс. Однако наследование является переходным. Если ClassC является производным от ClassB, а ClassB является производным от ClassA, ClassC наследует элементы, объявленные в ClassB и ClassA.
https://msdn.microsoft.com/en-us/library/ms173149.aspx
Вы не можете наследовать от всех типов.NET, но вы можете написать методы расширения для них.
Предполагая, что вы можете изменить существующий класс, вы должны пометить свой метод как виртуальный.
Это позволит вам обеспечить реализацию по умолчанию (то, что будет использоваться в вашем существующем коде) и иметь возможность переопределить ее при необходимости.
Ваш базовый класс может быть чем-то вроде:
public class TableMaker
{
public virtual string MakeTable()
{
//Provide default implementation used by existing code here
}
}
Ваш наследующий класс может затем переопределить виртуальный метод:
public class SpecialTableMaker : TableMaker
{
public override string MakeTable()
{
//Provide specific implementation for cell text here
}
}
Ваш существующий код будет работать нормально, и вы можете использовать этот другой класс там, где он вам нужен.
Я наконец-то закончил с этим решением. Это было предложено @codenoir, однако у меня также есть код, который демонстрирует целый механизм.
public class MyTable
{
public delegate string OnInsertHandler();
public event OnInsertHandler OnInsert;
public string Show()
{
string res = "-BEGIN-";
if (OnInsert != null) {
res += OnInsert ();
} else {
res += "#default insert#";
}
res += "-END-";
return res;
}
}
public class DelegateTester
{
public void OnTest()
{
MyTable mt = new MyTable();
Debug.Log("Default output: " + mt.Show()); // Shows "-BEGIN-#default insert#-END-"
// Changing functionality via delegate
mt.OnInsert += MyCustomInsert;
Debug.Log("Customized output: " + mt.Show()); // Shows "-BEGIN-#custom insert#-END-"
// Remove delegate
mt.OnInsert -= MyCustomInsert;
Debug.Log("Rollbacked output: " + mt.Show()); // Shows "-BEGIN-#default insert#-END-"
}
public string MyCustomInsert()
{
return "#custom insert#";
}
}
В этом примере я использую класс MyTable, который расширяется с помощью делегата Func. Таким образом, я могу позволить пользователям моего программного модуля расширять только один метод, не мешая другим классам и объектам.