4

My understanding of inheritance is pretty basic.

I want to create a base class, which implements IDisposable and then let other classes with functionality inherit from that base class, so that they share a base type.

It would allow me to put every object into one list, so that I can dispose of everything in one go, when I want to clean up. The thing is, a class in C# can only inherit once and otherwise only use interfaces.

Now, how can classes like Thread, inherit from my base class without me having to basically code the Thread class all over again?

It may sound dumb, but in short: I want to let already existing classes inherit a base class of my choosing without loosing its functionality. (So that all classes used in a project have a common base, to be summed up into one object type, for like List)

Is that even possible?

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
Rakku
  • 55
  • 4
  • *The thing is, a class in C# can only inherite once and otherwise only use interfaces* - who told you this? There is no practical limit to the depth of an inheritance tree – Caius Jard Jan 28 '21 at 09:09
  • *I want to let already existing classes inherite a baseclass of my choosing* - did you write these "already existing" classes? *how can classes like Thread, inherite from my baseclass without me having to basicly code the Threadclass* - they can't – Caius Jard Jan 28 '21 at 09:10
  • Each class can only inherit from one base class, but that the next class can inherit that class and a next class. There's no real limit. – SimonC Jan 28 '21 at 09:10
  • *Is that even possible?* - everything in c# already inherits from Object but you cannot write code that changes what another class inherits from without having the source code to the other class – Caius Jard Jan 28 '21 at 09:11
  • @CaiusJard No, he's referring to objects from the .Net framework. – SimonC Jan 28 '21 at 09:11
  • Sorry for the confusion, @SimonC is right, these are classes of the .Net framework. I basicly want to change the baseclass to a common one for all classes I want to use in a project. – Rakku Jan 28 '21 at 09:12
  • You misunderstood the concept **The thing is, a class in C# can only inherit once and otherwise only use interfaces** meaning that a class can inherit from only one class *directly* at the same time. – Miraziz Jan 28 '21 at 09:13
  • @CaiusJard the thing is, unfortunaly the baseclass object does not implement the IDisposable interface, so I cant use List and then clean up the objects in the list with .Dispose(). – Rakku Jan 28 '21 at 09:14
  • @Jamiec wait what? Did I miss something then? As far as I know a List can only take one object type at a time, or am I mistaken? Even if not, I´d have to use different foreach for every different object type, to use .Dispose() – Rakku Jan 28 '21 at 09:16
  • @Rakku you can have a list where the type is an interface. Se my answer. – Jamiec Jan 28 '21 at 09:18
  • @Jamiec Your link isnt working for me unfortunaly. – Rakku Jan 28 '21 at 09:18
  • @Rakku it was to [XYProblem](http://xyproblem.info) - I still think you're asking about how you _think_ something should be solved and not the actual issue you're facing. Have a read. – Jamiec Jan 28 '21 at 09:19

3 Answers3

6

If your aim is to simply store a list of objects which can be disposed, then you want a List<IDisposable>. Any class which, directly or indirectly implements that interface can be stored therein.

var disposables = new List<IDisposable>();
disposables.Add(new MyClass1());
disposables.Add(new SomeClass());
disposables.Add(new AnotherClass());

disposables.ForEach(d => d.Dispose());

Whether this is a worthwhle pattern, I'm not convinced!

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • Woah, I didnt know I could just use a interface as a listtype! Thats a great shortcut. What kind of pattern would you use to clean up? – Rakku Jan 28 '21 at 09:20
  • Not this one! The thing is you rarely have a completely disparate list of random classes that need cleaning up all in one go. Whichever class instantiates an object should be responsible for cleaning up afterwards. – Jamiec Jan 28 '21 at 09:22
  • Ah now I see where the misunderstanding is. I didnt want to use this pattern to clean up complete classes. This pattern is used in every class where the class cleans up its components which I instantiated. The list holds components, not whole classes. I had the idea, that I had to create more then one list for components which dont share a common parent (which has the IDisposable implemented). But since I now can just put everything in one list, which just uses the interface, that problem that I had, is gone. – Rakku Jan 28 '21 at 09:35
  • @Rakku If you found the answer to your problem, please mark one answer as accepted. – Michał Turczyn Jan 29 '21 at 10:21
3

Example you given invlolves interface IDisposable. In C#, class can implement multiple interfaces.

On the other hand, in C# class may inherit from exactly one class.

Having said that, it is not always good idea to inherit from classes, as it very limiting. Instead I would suggest composition: wiki

For example, I would suggest something like composition design pattern (it is a small variation, as the composite does not have collection of objects, rather just one object):

public interface IFoo
{
    void DoFooStuff();
}

public class Foo : IFoo
{
    public void DoFooStuff() {...};
}

public class ShouldImplementFoo : IFoo
{
    // Composition, you need to initialize it some time
    private Foo _foo;
    
    public void DoFooStuff() { _foo.DoFooStuff(); }
}

EDIT

After rethinking your problem, you seem to want to put some set of objects (of different classes) in a list, so you can execute some defined action on each object in a list.

The simpliest is: define interface with your defined action:

public interface IMyIntf
{
    void MyDesiredAction();
}

And now, make all classes implement it. Now you might think "Well, now I need to implement this method everywhere..." - nothing like that! Just use adapter design pattern, for example, having class:

public class MyConcreteClass
{
    public void ActionIWishToExecuteOnThisObject() 
    { ... }
}

you just modify it to:

public class MyConcreteClass : IMyIntf
{
    public void ActionIWishToExecuteOnThisObject() 
    { ... }

    // implement interface
    public void MyDesiredAction()
    {
        ActionIWishToExecuteOnThisObject();
    }
}

Now, you can use some aggregate, like List<IMyIntf>, place all objects you are interested in there and do:

foreach(var item in myList)
    item.MyDesiredAction();
Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
1

A class can inherits from an ancestor class (else Object, the root of all).

Also it can implements some interfaces (or none).

A class can have non implemented members as being abstract, so the class is abstract.

Also members can be virtual to enable polymorphism (abstract members are).

Once implemented, a thing is available in the class that can be instantiated for real if not abstract, and is available for all children too, except whose that are private which are hidden in subclass.

There is no need to repeat and that is one of the power of OOP.

Doing so, using abstraction, encapsulation, inheritance and polymorphism, after stuying the real world and the domain where we work, we can design a projection of this real world, a view in our mind, with concepts having data (fields and properties) and operations (methods), classed in artifacts (objects) and things like relations, composition, aggregation, interfaces, components, controls, and so on.

Thus we can factorize processings to not repeat like for example:

  • Having a Animal class and Cat and Dog child classes,
  • We put in animal the Size and the Color aspect,
  • As well as the Eat and Walk methods implemented for all animals,
  • And an abstract non-implemented DoSound.

Therefore:

  • In concrete classes Cat and Dog we don't implement again the things,
  • Except DoSound that is particular for each real animal gender.

Concerning interfaces, they are virtual contracts.

For example we can have animals and buildings that have nothing in common, at first look (we will not go back to atoms and photons), but we want to be able to manage instances of objects like cat and dog, as well as house and museum to take a photo.

To acheive that we define an interface IPhotoTaking and when defining previous classes, we add that they implements this interface.

Code sample:

public interface IPhotoTaking
{
  Image TakePhoto();
}
public abstract class Animal : IPhotoTaking
{
  public int Size { get; set; }
  public Color Color { get; set; }
  public void Eat() { ... }
  public void Walk() { ... }
  public abstract void DoSOund();
  public Image TakePhoto();
}

public class Cat : Animal // no need to repeat IPhotoTaking
{
  public override void DoSound() { ... }
}

public class Dog : Animal
{
  public override void DoSound() { ... }
}
public abstract class Building :IPhotoTaking
{
  public Image TakePhoto();
}

public class House : Building
{
}

public class Museum : Building
{
}

Now having this list we can use polymorphism like that:

var animals = new List<Animal>();

foreach ( var animal in animals )
  animal.DoSound();

Also without polymorphism and because C# does not support true polymorphism with the diamond operator yet applied on List<> here, we can use the interface like that:

var items = new List<IPhotoTaking>();

foreach ( var item in items )
  item.TakePhoto();

Remark: if taking a photo may be different for each types, we can set it virtual to specialize its implementation in each.

OOP Basic Principles

What is abstraction in C#?

How to choose between public, private and protected access modifier?

Association, Composition and Aggregation

What is polymorphism?

What is the difference between an interface and a class?

About the lack of true generic polymorphism and the missing diamond operator in C#

  • Thank you, the explanation was very helpful, unfortunaly I can only mark one answer, but yours was extremly good as well :)! – Rakku Jan 29 '21 at 12:12
  • @Rakku Just choose the one that best explains things to you and helps you achieve your goal the way you feel best to have simple, clean, short, understandable, maintainable, elegant, robust, secure and well effective without spaghetti. –  Jan 29 '21 at 12:20