英文:
How to make a interface base property, then implement with the derived?
问题
我正在创建一个聊天应用程序。在聊天中,用户可以发送三种类型的消息:图片、文件和文本消息。我正在尝试创建一个名为IMessege
的接口,其中包含3个类属性:
interface IMessege
{
object content { get; }
User sender { get; }
DateTime sent { get; }
}
然后,我想在3个类中实现这个接口:FileMessege
、ImageMessege
和StringMessege
。我希望它们都具有User sender
和DateTime sent
,但content
的类型在StringMessege
中是string
类型,在FileMessege
中是file
类型等等...
我没有认为这会成为问题,因为所有这些类都继承自object
,但显然它是一个问题。
我该如何做?
英文:
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?
答案1
得分: 4
// 选项1:使IMessage成为内容类型的泛型接口
interface IMessage<TContent>
{
TContent Content { get; }
User Sender { get; }
DateTime Sent { get; }
}
public class FileMessage : IMessage<File>
{
// ...
}
public class StringMessage : IMessage<string>
{
// ...
}
// 等等
优势:始终具有强类型
劣势:现在无法拥有(比如)List<IMessage>
。可以通过分离非泛型和泛型部分来缓解这一问题:
interface IMessage
{
User Sender { get; }
DateTime Sent { get; }
}
interface IMessage<TContent> : IMessage
{
TContent Content { get; }
}
// 选项2:使用显式接口实现
interface IMessage
{
object Content { get; }
User Sender { get; }
DateTime Sent { get; }
}
public class FileMessage : IMessage
{
// 对象类型的Content属性的显式接口实现
object IMessage.Content => Content;
// Content的常规强类型属性
public File Content { get; }
// 其他接口属性
}
// 等等
优势:不需要泛型
劣势:在使用接口时对内容的访问变得弱类型,并且代码稍微更复杂。
英文:
(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.
答案2
得分: 3
你可以使用一个通用接口。例如,
public interface IMessage<T>
{
T content { get; }
string sender { get; }
DateTime sent { get; }
}
现在你可以定义你的类如下:
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; }
}
或者,你可以定义一个单一的通用类Message,不过这将取决于类的其他职责。如果这些类之间唯一的区别是内容的类型,你也可以这样做(根据你的用例)。以下示例使用单一的通用类来实例化不同的实例(基于字符串、图像和文件的):
public class Message<T> : IMessage<T>
{
public T content { get; }
public string sender { get; }
public DateTime sent { get; }
}
现在你可以初始化不同的实例,例如:
var fileMessage = new Message<FileInfo>();
var stringMessage = new Message<string>();
var imageMessage = new Message<Image>();
英文:
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>();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论