Search code examples
c#inheritanceinterfacepolymorphismclass-properties

How to make a interface base property, then implement with the derived?


I am creating a chat app. In the chat, users can send three types of messages: images, files, and text messages. I am trying to create an interface called IMessege that contain 3 class properties:

interface IMessege
    {
        object content { get; }
        User sender { get; }
        DateTime sent { get; }
    }

Then I want to implement the interface in 3 classes: FileMessege, ImageMessege and StringMessege. I want them all to have User sender and DateTime sent, but the content I want to be from type string at StringMessege, from type file at FileMessege etc...

I did not think this is going to be a problem since all these classes inherit from object, but apparently it is.

how can I do it?


Solution

  • (I've changed the names in both options to be idiomatic C#.)

    Option 1: make IMessage generic in the type of content

    interface IMessage<TContent>
    {
        TContent Content { get; }
        User Sender { get; }
        DateTime Sent { get; }
    }
    
    public class FileMessage : IMessage<File>
    {
       ...
    }
    
    public class StringMessage : IMessage<string>
    {
       ...
    }
    
    // etc
    

    Advantage: always strongly typed
    Disadvantage: you now can't have (say) a List<IMessage>. You could mitigate this by separating out the non-generic and generic parts:

    interface IMessage
    {
        User Sender { get; }
        DateTime Sent { get; }
    }
    
    interface IMessage<TContent> : IMessage
    {
        TContent Content { get; }
    }
    

    Option 2: use explicit interface implementation

    interface IMessage
    {
        object Content { get; }
        User Sender { get; }
        DateTime Sent { get; }
    }
    
    public class FileMessage : IMessage
    {
        // Explicit interface implementation of the object-typed Content property 
        object IMessage.Content => Content;
    
        // Regular strongly-typed property for Content
        public File Content { get; }
    
        // Other interface properties
    }
    
    // etc
    

    Advantage: No need for generics
    Disadvantage: Weakly-typed access to content when using the interface, and slightly more complicated code.