Rusi Nova
Rusi Nova

Reputation: 2655

How to write a method that can be shared by two non-inherited class

I am having 2 classes, both having a same method(name + type +behavior) and a same property (name + type)

public class Country
{
    public string Name { get; set; }

    public void DisplayName()
    {
        Console.WriteLine(this.Name);
    }
}

public class Person
{
    public string Name { get; set; }

    public void DisplayName()
    {
        Console.WriteLine(this.Name);
    }
}

-- Person and Country classes are not allowed to inherit

In the above code you can see Person class has similar method(DisplayName) like Country class. I am looking for a way so that both classes can share the same method codes, i want to do this because in my real codes- Method which i want to share is very big and whenever i change code in one class i have to copy paste it in other class too. That i feel is not the correct way.

Please suggest how to resolve this problem.

Upvotes: 3

Views: 165

Answers (10)

kr.mayank1997
kr.mayank1997

Reputation: 21

You can define that big method in a separate class and then call the method in both the above classes. For a static method, you can call the method using classname.methodname() syntax.

For a non static method, you will have to do this:

classname obj=new classname();
obj.methodname();

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500385

A couple of options:

  • Make both classes implement an interface for the common members (Name) and add an extension method for the behaviour (or just a normal static method)
  • Create methods which take an instance and a lambda exppession to access the comment members, e.g.

    public static void Display<T>(T item, Func<T, string> nameGetter)
    

    You'd then call it with (say)

    DisplayHelper.Display(person, p => p.Name);
    

The interface solution is the cleaner one, but using a delegate is more flexible - you don't need to be able to change the classes involved, and you can cope with small variations (e.g. PersonName vs FooName vs Name)

Upvotes: 0

Patrick Karcher
Patrick Karcher

Reputation: 23603

You say they cannot inherit from a common base class, but you could add an interface, right? I suggest giving them each a common interface. Then define an extension method for that interface. The method will appear for each of them in VS.

(Assumption: this will work if the class members accessed by the extension methods are public or internal.)

interface IDisplayable
{
    string Name {get; set;}
}

public class Country : IDisplayable
{
    public string Name { get; set; }
}

public class Person : IDisplayable
{
    public string Name { get; set; }
}

public static void DisplayName(this iDisplayable d)
{
    return doSomeDisplayLogic(d.Name);
}

. . . And in the same class as your extension method, define (not as an extension method) a function doSomeDisplayLogic to do your common logic. (first-time gotcha: make sure the extension method is in the same Namespace or the its namespace is also included in the calling code.)

I don't know if you're new to extension methods or not. They are very powerful. (And like many powerful features, they can be abused). An extension method on an interface seems crazy at first, until you get straight in your head how extension methods really work. LINQ wouldn't work without this!

Update: I see your comment above that the classes can't inherit from a common class, because they are already inheriting from a common class (which I assume can't be messed with too much). I would like to point out an Option 2, based on this: Creating a new class that Country/Person/etc. will inherit from, that itself inherits from the existing common parent class. The existing base class would become a grandparent class, so to speak. This would become more the route to go if Country and Person have other common characteristics besides this DisplayName method. If DisplayName is all you're after, the Interface/Extension pattern might be better.

Upvotes: 2

Alex
Alex

Reputation: 23300

warning: lots of untested code here, wild guessing mostly since i disagree with the base assumption "no inheritance".

something like this should help you. create a new static class and paste your code in here.

public static class Display
{
    public static void DisplayName<T>(T obj)
    {
        if ((T is Person) || (T is Country) || (T is whateveryouwant))
        {
            //do stuff
        }
    }
}

in your classes, refactor ShowDisplayName() to call that with "this" as parameter.

... public void DisplayName() { DisplayName(this); } ...

I wonder why your classes are not allowed to inherit it from a base class, since that's imho the right-est way to solve this.

Upvotes: 0

DRapp
DRapp

Reputation: 48139

What I THINK you are asking for is multiple class inheritance which is not allowed in C#. (but can be with C++ which you are NOT doing).

All the others have identified doing an INTERFACE solution, and probably the best way to go. However, from your description, you have a SINGLE BLOCK of code that is identical regardless of the type of object being a person or a business. And your reference to a huge block of code, you don't want to copy/paste that same exact code among all the other classes that may be intended to use similar common "thing" to be done.

For simple example, you have a functionality that builds out a person's name and address (or business name and address). You have code that is expecting a name and up to 3 address lines, plus a city, state, zip code (or whatever else). So, the formatting of such name/address information is the same for a person vs a business. You don't want to copy this exact method over and over between the two. However, each individual class still has its own things that it is responsible for.

I know its a simple example for context, but I think gets the point across.

The problem with just defining an Interface is that it won't allow you to actually implement the CODE you are referring to.

From your sample, I would consider doing a combination of things.. Create a static class with methods on it that you might want as "globally" available. Allow a parameter to be passed into it of an instance of a class that has a type of interface all the others have expressed that will guarantee the incoming object has all the "pieces" of properties / methods you are expecting, and have IT operate on it as needed. Something like

public interface ITheyHaveInCommon
{
   string Name;
   string GetOtherValue();
   int SomethingElse;
}

public class Person : ITheyHaveInCommon
{
  // rest of your delcarations for the required contract elements
  // of the ITheyHaveInCommon interface...
}

public class Country : ITheyHaveInCommon
{
  // rest of your delcarations for the required contract elements
  // of the ITheyHaveInCommon interface...
}


public static class MyGlobalFunctions
{
   public static string CommonFunction1( ITheyHaveInCommon incomingParm )
   {
      // now, you can act on ANY type of control that uses the 
      // ITheyHaveInCommon interface...
      string Test = incomingParm.Name
                  + incomingParm.GetOtherValue()
                  + incomingParm.SomethingElse.ToString();

      // blah blah with whatever else is in your "huge" function

      return Test;
   }
}

Upvotes: 0

sll
sll

Reputation: 62504

I would suggest to avoid Extension Methods in some cases, you can ran into a problem when you need slightly a different implementation for both classes and then you have to design a more generic solution, EM can cause the same issues like multiple inheritance does.

As more generic OOD solution I would suggest to extract this behaviour into a separate service class abstracted by an interface:

public interface IDisplayService()
{
    void Display();
}

Then implement it and inject into both classes via constructor.

Also, instead of introducing the interfaces and new classes you can inject Action or Func<> via constructor or even property and then call this method by invoking an injected in delegate.

Upvotes: 1

Paolo Tedesco
Paolo Tedesco

Reputation: 57202

You could use composition: define an interface, a class that implements it, and then have Person and Country implement the interface by calling methods on the implementation class:

// the interface
public interface IName {
    string Name { get; set; }
    void DisplayName();
}

// a class that implements the interface with actual code
public class NameImpl : IName {
    public string Name { get; set; }

    public void DisplayName() {
        Console.WriteLine(this.Name);
    }
}

public class Country : IName {

    // instance of the class that actually implements the interface
    IName iname = new NameImpl();

    // forward calls to implementation
    public string Name {
        get { return iname.Name; }
        set { iname.Name = value; }
    }

    public void DisplayName() {
        // forward calls to implementation
        iname.DisplayName();
    }
}

Upvotes: 0

Ilia G
Ilia G

Reputation: 10211

Define an interface

public interface INameable
{
    string Name {get;}
}

then add an extension

public static class INameableExt
{
    public static void DisplayName(this INameable n)
    {
        // do your thing
    }
}

Upvotes: 1

jason
jason

Reputation: 241641

You could implement a strategy pattern:

class DisplayNameStrategy<T> {
    private readonly Func<T, string> nameSelector;
    public void DisplayNameStrategy(Func<T, string> nameSelector) {
        this.nameSelector = nameSelector;
    }

    public void abstract DisplayName(T t);
}

class WriteToConsoleDisplayNameStrategy<T> : DisplayNameStrategy<T> {
    public void WriteToConsoleDisplayNameStrategy(Func<T, string> nameSelector)
        : base(nameSelector) { }
    public override void DisplayName(T t) {
        Console.WriteLine(this.nameSelector(t));
}

public class Person {
    private readonly DisplayNameStrategy<Person> displayNameStrategy =
        new WriteToConsoleDisplayNameStrategy<Person>(x => x.Name);

    public string Name { get; set; }

    public void DisplayName() {
        this.displayNameStrategy(this);
    }
}

Note: it's probably better to inject the concrete strategy.

Upvotes: 0

BrokenGlass
BrokenGlass

Reputation: 160882

You could create either a static utility method DisplayName() that you pass the data needed for display, or use composition and move all properties and corresponding methods such as DisplayName() in a separate class - then use an instance of this class from both Country and Person.

Upvotes: 0

Related Questions