0

I have to implement something like this

class Base1 {
    [StringLenght(100), MaxLenght(100)]
    public string Name {get;set;}
}

class Base2 {
    [StringLenght(100), MaxLenght(100)]
    public string Address {get; set;}
}

class ClassA: Base1, Base2 { 
    public string City {get;set;}
}

class ClassB: Base1, Base2 { 
    public string Country {get;set;}
}

class ClassC and so on.

C# does not support multiple inheritance and I can use Interfaces, but If i use interfaces I have to implement every property in every class and I don't wont to do this. I want to write only once the Name property with it's attribute because in every object I need it it has the same properties and attributes.

Is this possibile in some way?

Davide Martelli
  • 179
  • 1
  • 3
  • 9
  • 5
    Use composition. – Alexander Petrov Dec 13 '22 at 18:06
  • You'll need to use delegation or composition (hand write code to call 2nd base class), just like VB6, which didn't even have single inheritance. You might be able to do monkey patching, e.g. https://stackoverflow.com/questions/4538017/monkey-patching-in-c-sharp – MatthewMartin Dec 13 '22 at 18:06
  • What do you want to do? Maybe we can change the method based on what you want to do. I asked this question because based on your question if you don't use each of classes `Base1` or `Base2` separately, there is no need to divide them into two different classes – Hamid Mohammadi Dec 13 '22 at 18:42
  • 2
    You've spelt length wrong in your attribute everywhere – ScottishTapWater Dec 13 '22 at 19:16
  • I think I'm inside a problem with the wrong answer. My goal is to build a database (because the classes are the entities of the db) where all the "Name" properties in all tables have the same attribute like length, type etc... Because every time I found my tables one with Name nvarchar(50), sometimes 100 etc... The same for some other fields with the same purpose. I'm sorry but I think I've started a question in a very bad way :) – Davide Martelli Dec 13 '22 at 20:05

2 Answers2

0

Either use composition or inherit these properties from interfaces. That's it.

If you use interfaces it's as simple as redefining Base2 and Base2 as interfaces, but you will have to implement those interfaces in ClassA and ClassB, and you will have to move your validation attributes down into those classes (ie duplicate them).

class I1 {
    string Name {get;set;}
}

class I2 {
    string Address {get; set;}
}

class ClassA: I1 , I2 {
    [StringLenght(100), MaxLenght(100)]
    public string Name {get;set;}
    [StringLenght(100), MaxLenght(100)]
    public string Address {get;set;}
}

class ClassB: I1 , I2 { 
    [StringLenght(100), MaxLenght(100)]
    public string Name {get;set;}
    [StringLenght(100), MaxLenght(100)]
    public string Address {get;set;}
}

If you want to re-unite the validation, pull it out of the classes, if your framework supports that.


public class I1Validator : AbstractValidator<I1>
{
    public I1Validator()
    {
        _ = RuleFor(q => q.Name).NotNull()...etc;
    }
}

Otherwise, use composition.

class ClassA
{
   public Base1 Base1 {get;}
   public Base2 Base2 {get;}
}

or, if you want to to feel like it isn't composition you can do this.

class ClassA
{
   private readonly Base1 _base1;
   private readonly Base2 _base2;
   public string Name => _base1.Name;
   public string Address => _base2.Address;
}

Those are the choices.

Or those are the choices if they need to have a relationship. I've written systems where lots of entities have a string called Name, but that doesn't necessarily mean there was any relationship between those names or any utility in creating such a relationship. Is your model actually just this?:

class Class1 {
    [StringLenght(100), MaxLenght(100)]
    public string Name {get;set;}
    [StringLenght(100), MaxLenght(100)]
    public string Address {get;set;}
}

class Class2 { 
    [StringLenght(100), MaxLenght(100)]
    public string Name {get;set;}
    [StringLenght(100), MaxLenght(100)]
    public string Address {get;set;}
}

Out of these, composition is most like multiple inheritance, and is probably what you intend. Does it have boilerplate: Yes. Some languages (like Golang) do the Name => _base1.Name stuff by magic, but in C# there is no such magic.

Nathan Cooper
  • 6,262
  • 4
  • 36
  • 75
-1

Multiple inheritance isn't supported in C#, for good but boring reasons that I won't go into in this answer.

The correct way to do this is to make an interface for each set of functionality that is separately required, like you said. You're right that this requires some boilerplate code, but traditional way of doing what you're asking, if the required functionality is simple (like just adding a property). It allows you to specify what classes have what properties, without creating a messy class hierarchy.

So something like this:

public interface IHasName
{
    public string Name { get; set; }
}

public interface IHasAddress
{
    public string Address { get; set; }
}

public class HasAName : IHasName
{
    public string Name { get; set; }
}

public class HasAddress : IHasAddress
{
    public string Address { get; set; }
}

public class HasANameAndAddress : IHasName, IHasAddress
{
    public string Name { get; set; }
    public string Address { get; set; }
}

You said you have concerns about implementing every property on every class, but it is the recommended way of getting around multiple-inheritance related situations.

You can of course go down the composition route instead which is a good move for more complex scenarios, but for this simple scenario it will create more bloat classes and more setup/boilerplate for each property.


That being said...

The properly implemented interfaces are the right way to go here, but I'm going to present a hacky way of avoiding the boilerplate, if you feel you really need to.

If you really really want to avoid boilerplate, you can abuse Extension methods and Interfaces so that you can simulate arbitrary properties on interfaces without actually including them in the interface, like so:

public interface IHasName { }

public static class Extensions
{
    public static Dictionary<IHasName, string> nameLookup = new Dictionary<IHasName, string>();
    public static string GetName(this IHasName obj)
    {
        if(nameLookup.TryGetValue(obj, out var name))
        {
            return name;
        }
        return null;
    }

    public static void SetName(this IHasName obj, string name)
    {
        nameLookup[obj] = name;
    }
}

Here, there's an interface called IHasName, but it doesn't actually contain a string Name property on it, it's just empty. We then create an Extensions class that has a backing Dictionary that stores a name value in that instead, and Get/Set methods to read/write to that dictionary.

So from here, you can do this:

public class SomeClassWithAName : IHasName
{
}

And read/write it's name property like this:

var a = new SomeClassWithAName();

a.SetName("Greg");
Console.WriteLine(a.GetName());

From here you could extend this to add a IHasAddress interface and another group of get/set address extension methods with another backing dictionary. This would mean you could then do this:

public class SomeClassWithANameAndAddress : IHasName, IHasAddress
{
}

And set up your classes by just attaching the relevant interfaces without having to add boilerplate properties to every class.

Note again: this is slightly hacky way around your issue of trying to reduce repeated code. If it's not suitable, use standard interfaces or composition.

John
  • 500
  • 4
  • 15