1

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?

avivgood2
  • 227
  • 3
  • 19
  • 5
    Sounds like your interface should probably be generic in "the type of content". You *could* use an explicit interface implementation, but it's probably cleaner to make it generic. I'll add both options as answers. – Jon Skeet Jan 03 '20 at 16:44

2 Answers2

4

(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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • as for solution 1, fix to List, can I access ```Content ``` from a ```IMessage```? because it seems like only ```sender``` and ```sent``` can be accessed. – avivgood2 Jan 03 '20 at 17:43
  • @avivgood2: No, the non-generic interface doesn't have content at all. If you *want* to be able to get any content, but in a weakly-typed way, then the second option is probably better. – Jon Skeet Jan 03 '20 at 18:24
3

You could use a generic Interface.For example,

public interface IMessage<T>
{
    T content { get; }
    string sender { get; }
    DateTime sent { get; }
}

Now you can define your classes as

public class StringMessage:IMessage<string>
{
    public string content { get; }
    public string sender { get; }
    public DateTime sent { get; }
}

public class FileMessage:IMessage<FileInfo>
{
    public FileInfo content { get; }
    public string sender { get; }
    public DateTime sent { get; }
}

public class ImageMessage:IMessage<Image>
{
    public Image content { get; }
    public string sender { get; }
    public DateTime sent { get; }
}

Alternatively, you could define a single generic class Message,however, that would depend on the other responsibilities of the class. If only difference between the classes are the type of content, you could use following too (depending on your usecase). The following example, uses a single generic classes to instantiate different instances (string,image,file based).

public class Message<T>:IMessage<T>
{
    public T content { get; }
    public string sender { get; }
    public DateTime sent { get; }
}

You could now initialize your different instances as

var fileMessage = new Message<FileInfo>();
var stringMessage = new Message<String>();
var imageMessage = new Message<Image>();
Anu Viswan
  • 17,797
  • 2
  • 22
  • 51
  • @Jon Skeet has a point. if I make the interface generic, I can not use lists of messages, and then what is the point of the interface anyway? – avivgood2 Jan 03 '20 at 17:02
  • @avivgood2 The idea of splitting the generic and non-generic part of interface as suggested by Jon would be a good idea in this case, while still having the benefits of strongly typed content – Anu Viswan Jan 03 '20 at 17:10