2016-11-10 3 views
-1

У меня есть хороший полный класс, который делает потрясающие вещи. Мне нужно разрешить пользователям использовать этот класс, заменив в нем некоторые методы, но наследование не допускается, потому что этот класс также используется в других классах приложений.Способ расширения существующего класса без создания нового класса в C#

Это похоже на то, что у вас есть класс, который создает таблицу, но вы должны разрешить пользователям переопределять метод, который создает ячейку таблицы, чтобы пользователь мог напечатать что-то пользовательское в этой ячейке. Класс, однако, имеет способ по умолчанию для печати содержимого ячейки (в случае, если пользователю не нужно его настраивать).

Есть ли общий или стандартизированный способ достижения этого?

+3

Не могли бы вы объяснить, почему наследование запрещено? Вы говорите, что этот класс также используется в других классах приложений. Так? Наследование не изменит поведение базового класса, а только подклассы. Это звучит как идеальный кандидат на наследование. – adv12

+0

@ adv12 Потому что у меня есть что-то вроде 10 классов в этом приложении, которое использует базовый класс. Наследование означает, что пользователю нужно будет изменить еще 10 классов, чтобы позволить им использовать унаследованный класс вместо исходного. – Epsiloncool

+1

Нет. Наследование от базового класса не окажет никакого влияния на любое использование существующего класса (если вы не сделаете каких-либо изменений в базе - например, отметьте его абстрактным) - это звучит как главный кандидат на наследование. – Theo

ответ

4

Обновлено

Достигнув «арахисовое галереи» отмечают, что мой подход (в нижней части) не будет соответствовать законопроект, вот еще один способ:

Использование делегации. Определите определенные общедоступные свойства с помощью типа 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, но вы можете написать методы расширения для них.

+0

* вы можете написать для них методы расширения * - true, но вы не можете ** переопределить ** их методы. –

+0

@ Ивана, если класс не запечатан, вы * можете * использовать переопределения. И если вам удобно отражать, вы можете даже изменить методы в закрытом классе. –

+0

Комментарий был касается * методов расширения *. –

0

Предполагая, что вы можете изменить существующий класс, вы должны пометить свой метод как virtual.

Это позволит вам предоставить реализацию по умолчанию (это то, что будет использовать ваш существующий код), и иметь возможность переопределить ее при необходимости.

Ваш базовый класс может быть что-то вдоль линий:

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

Вы существующий код будет работать нормально, и вы можете использовать этот другой класс, где вам это нужно.

+0

Да, это было бы просто, но у меня есть что-то вроде 10 других классов в моем приложении, которое использует класс «TableMaker». И я хочу, чтобы они полностью остались нетронутыми. – Epsiloncool

+0

@ Epsiloncool. Нет причин менять другие классы. У вас уже есть открытый метод на TableMaker, все, что вам нужно сделать, это сделать его виртуальным ... Если по какой-то причине вы не можете проверить мой ответ –

+0

Как вы можете объяснить другим классам использовать новый класс (расширенный) вместо старого? – Epsiloncool

-1

Я, наконец, закончил это решение. Это было предложено @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. Таким образом, я могу разрешить пользователям моего программного модуля распространять только один метод без каких-либо проблем с другими классами и объектами.

+0

Этот подход отрицает цель иметь класс в первую очередь. Речь идет о классическом сценарии, который можно и нужно решать с наследованием и переопределяемыми членами. Предлагаемое решение является скорее взломом, чтобы восполнить недостаток понимания концепций ООП. – JuanR

+0

@Juan Почему вы так уверены, что концепция ООП может охватить всю цель? Я не уверен. По крайней мере, я не могу решить свою первоначальную задачу, используя концепции ООП. Можете ли вы предложить чистое и дешевое решение? – Epsiloncool

+0

Я уже сделал @ Epsiloncool. См. Мой ответ ниже. Я рад помочь вам в дальнейшем, но вам нужно будет предоставить больше кода, в частности, той части, где вы действительно используете класс MyTable. Быстрого модульного теста недостаточно, чтобы понять, как вы его используете. – JuanR

 Смежные вопросы

  • Нет связанных вопросов^_^