1

I have a good complete class which is doing awesome things. I need to allow users to use this class by replacing some methods in it, but inheritance is not allowed, because this class also used in other application classes.

It is like you have a class which creating a table, but you need to allow users to redefine method which is creating table cell to let the user print something custom in this cell. The class, however, has a default way to print the cell content (in case the user do not need to customize it).

Is there any common-used or standartized way to achieve this?

Epsiloncool
  • 1,435
  • 16
  • 39
  • 4
    Could you explain better why inheritance is not allowed? You say this class is also used in other application classes. So? Inheritance won't change the behavior of the base class, only the subclasses. This sounds like a perfect candidate for inheritance. – adv12 Nov 10 '16 at 21:38
  • @adv12 Because I have something like 10 classes in this application which is using basic class. Inheritance means the user will need to change other 10 classes too to let them use inherited class instead of original one – Epsiloncool Nov 10 '16 at 22:29
  • 1
    No so. Inheriting from a base class will have no impact on any use of the existing class (provided you dont make any breaking changes to the base - like mark it abstract) - this sounds like a prime candidate for inheritance. – Theo Nov 10 '16 at 22:31
  • 1
    @Epsiloncool, that is true if those classes are creating their own instances of the base class. But that's not typically how you'd set up an application if you were anticipating the sort of functionality you desire. To make it all work, you'd have to pass the objects into those classes from an external class that knew whether to use the base class or a subclass. The 10 classes using the objects wouldn't have to care whether they were actually instances of the base class or the subclasses. – adv12 Nov 10 '16 at 22:34
  • Yeah, passing new class objects to other 10 classes looks like a big patch. Thats why I am looking for a better solution. – Epsiloncool Nov 10 '16 at 22:42
  • 1
    passing new class objects to other 10 classes is the BEST solution, the other solutions are actually patches. – Arturo Menchaca Nov 10 '16 at 22:46

3 Answers3

7

Updated

Having had "the peanut gallery" point out that my approach (at bottom) wouldn't fit the bill, here's another way:

Use delegation. Define certain public properties with type Action or Func. Where these behaviors need to be invoked in your code, compare the properties to null. If null, use your default behavior. If not, invoke the values.

Your calling code MAY set the properties, but doesn't have to.

(first try) Alternative approaches:

You are describing an extension method, or the use of inheritance if that's available.

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C# and Visual Basic, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.

https://msdn.microsoft.com/en-us//library/bb383977.aspx

Inheritance, together with encapsulation and polymorphism, is one of the three primary characteristics (or pillars) of object-oriented programming. Inheritance enables you to create new classes that reuse, extend, and modify the behavior that is defined in other classes. The class whose members are inherited is called the base class, and the class that inherits those members is called the derived class. A derived class can have only one direct base class. However, inheritance is transitive. If ClassC is derived from ClassB, and ClassB is derived from ClassA, ClassC inherits the members declared in ClassB and ClassA.

https://msdn.microsoft.com/en-us/library/ms173149.aspx

You can't derive from all .NET types, but you can write extension methods for them.

Community
  • 1
  • 1
Xavier J
  • 4,326
  • 1
  • 14
  • 25
  • *you can write extension methods for them* - true, but you cannot **redefine** their methods. – Ivan Stoev Nov 10 '16 at 21:42
  • @Ivan actually, unless a class is sealed, you *can* through the use of overrides. And if you're handy with reflection, you can even change the methods in a sealed class. – Xavier J Nov 10 '16 at 21:43
  • The comment was regarding *extension methods*. – Ivan Stoev Nov 10 '16 at 21:48
  • @IvanStoev You can if you use `override` or `virtual` method definitions. – Uchiha Itachi Nov 10 '16 at 21:50
  • 1
    @GeoffOverfield I start regretting for posting the comment. Saying it again in plain English, the comment was only about [**Extension methods**](https://msdn.microsoft.com/en-us/library/bb383977.aspx) – Ivan Stoev Nov 10 '16 at 21:56
  • @IvanStoev I didn't use the word **redefine** nor did the examples from MSDN. You are stuck on semantics over a word in the original post. Not sure why you've singled out my response. If you want to mince over the correct words to use in a sentence, there's a whole other stackexchange for that. Have fun! – Xavier J Nov 10 '16 at 21:59
  • Didn't catch that. My bad buddy. – Uchiha Itachi Nov 10 '16 at 22:14
  • @codenoir OP specifically states that he want to allow *replacing some methods* and also *redefine method*. Also *inheritance is not allowed*. Which makes both your points invalid, hence answering a question that is not asked. Take care. – Ivan Stoev Nov 10 '16 at 22:16
  • @IvanStoev is right. Extention methods are useless in this case(In any case, they are just syntactic sugar ) and the OP said he doesn't want to use inheritance... – George Vovos Nov 10 '16 at 22:22
  • Got it. Ivan, my apologies. See my changes above. – Xavier J Nov 10 '16 at 22:27
  • The reason why I don't want to use inheritance is because inheritance means creating NEW class, which is only usable for user's application, but not for other mine module classes (my module classes will not know anything about user's new class). – Epsiloncool Nov 10 '16 at 22:38
  • I think delegate with Func should be good to solve my problem. I gonna try it and put a word here in case it fits or not – Epsiloncool Nov 10 '16 at 22:38
  • And delegation will work, but the delegate cannot access private or protected methods, properties, or fields. – Xavier J Nov 10 '16 at 22:42
  • @codenoir Thanks, delegates way works very good. I also put some code below to demonstrate how it works. – Epsiloncool Nov 10 '16 at 23:12
1

Assuming you are able to modify the existing class, you should be marking your method as virtual.

This will allow you to provide a default implementation (which is what your existing code will use) and be able to override it with a custom one where needed.

Your base class could be something along the lines of:

public class TableMaker
{
    public virtual string MakeTable()
    {
        //Provide default implementation used by existing code here
    }
}

Your inheriting class can then override the virtual method:

public class SpecialTableMaker : TableMaker
{
    public override string MakeTable()
    {
        //Provide specific implementation for cell text here
    }
}

You existing code will work just fine and you can use this other class where you need it.

JuanR
  • 7,405
  • 1
  • 19
  • 30
  • Yeah it would be simple, but I have something like 10 other classes in my application which uses "TableMaker" class. And I want them to stay untouched completely – Epsiloncool Nov 10 '16 at 22:31
  • @Epsiloncool There is no reason to change the other classes.You already have a public method on TableMaker,all you have to do it make it virtual... If for some reason you can't check my answer – George Vovos Nov 10 '16 at 22:34
  • How you can explain to other classes to use new class (extended) instead of old one? – Epsiloncool Nov 10 '16 at 22:40
-1

I've finally ended with this solution. It was proposed by @codenoir, however I also have a code which demonstrates a whole mechanism.

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#";
    }
}

In this example I am using MyTable class which is extended using Func delegate. This way I can allow to users of my software module to extend only one method without make any mess with others classes and objects.

Epsiloncool
  • 1,435
  • 16
  • 39
  • This approach negates the purpose of having the class in the first place. The issue at hand is a classic scenario that can and should be addressed with inheritance and overridable members. The proposed solution is more of a hack to make up for the lack of understanding of OOP concepts. – JuanR Nov 12 '16 at 02:36
  • @Juan Why you are so sure that OOP concept can cover all goal? I am not so sure. At least I can not solve my initial task using OOP concepts. Can you propose clean and cheap solution? – Epsiloncool Nov 12 '16 at 10:46
  • I already did @Epsiloncool. See my answer below. I am happy to help you further but you will need to share more code, in particular, the part where you actually use the MyTable class. A quick unit test is not enough to understand how you are using it. – JuanR Nov 12 '16 at 21:52