Home > front end >  Is it possible to inherit 1 interface or another? (.NET 4.8 Framework)
Is it possible to inherit 1 interface or another? (.NET 4.8 Framework)

Time:01-03

I have this 2 interfaces:

internal interface ITexture
{
    string Texture { get; set; }
}

internal interface IBackTexture
{
    string BackTexture { get; set; }
}

Where, for context, not all Textures have a Back Texture and not all Back Textures have a Texture.

public void TextureMerger<T>(...) where T : ITexture,IBackTexture
{
    ...
}

This type of inheritance makes so that T needs to have both Texture and Back Texture.

Is there a way to make it so it is at least one of them?

CodePudding user response:

There is no way to describe type-safe union of two non-compatible types in C#. You can use type safe wrappers around private method accepting common base (i.e. object).

public void TextureMerger(ITexture t) => TextureMerger((object) t);
public void TextureMerger(IBackTexture t) => TextureMerger((object) t);
// to resolve ambiguous between the previous two overloads if class implements both
public void TextureMerger<T>(T t) where T : ITexture, IBackTexture => TextureMerger((object) t);

private void TextureMerger(object t)
{
    if (t is ITexture it)
    {
      // ...
    }
    if (t is IBackTexture ibt)
    {
      // ...
    }
}

Or introduce new common base (i.e. interface ITextureBase) to make them compatible.

interface ITextureBase { /*empty marker*/ }
interface IBackTexture : ITextureBase { /* ... */}
interface ITexture : ITextureBase { /* ... */}

And use it

public void TextureMerger(ITextureBase t) {}

CodePudding user response:

You could create a pointless base interface to relate the acceptable types like this,

using System;
                    
public class Program
{
    public static void Main()
    {
    }
    
    internal void TextureMerger<T>(params IPointlessBase[] pointlesslyBasedTextures) 
            where T : IPointlessBase
    {
        foreach(var pb in pointlesslyBasedTextures)
        {
            string textureString;
            switch (pb)
            {
                case ITexture t:
                    textureString = t.Texture;
                    break;
                    
                case IBackTexture bt:
                    textureString = bt.BackTexture;
                    break;
                    
                default:
                    throw new NotImplementedException(pb.GetType().Name);
            }
        }
    }
}

internal interface IPointlessBase
{
}

internal interface ITexture : IPointlessBase
{
    string Texture { get; set; }
}

internal interface IBackTexture : IPointlessBase
{
    string BackTexture { get; set; }
}

However, doing that feels like an anti-pattern, if your interfaces have something in common, then both those interfaces should have that property, so the property should be on the inherited base interface.

CodePudding user response:

Is there a way to make it so it is at least one of them?

No, not directly at least. Generic constraints allow you to restrict the type to allow you to access properties and methods on the generic type. If the type only needs to implement one you do not know what properties and methods are allowed to be called.

The simplest workaround would be to insert runtime checks.But I would probably consider if your model is correct. You might want to build a type that wraps the multiple possible states you want to describe:

public class Texture{
    public bool HasFront => string.IsNullOrWhitespace(FrontTexture);
    public bool HasBack => string.IsNullOrWhitespace(BackTexture);
    string FrontTexture;
    string BackTexture;
    private Texture(string front, string back){
      FrontTexture = front;
      BackTexture = back;
   }
   public static Texture CreateFront(string front) => new (front, null);
   public static Texture CreateBack(string back) => new (null, back);
   public static Texture Create(string front, string back) => new (front, back); 
   // Other methods to use the texture
}
  •  Tags:  
  • c#
  • Related