C# 有没有可能做到';递归参数多态性&x27;在C中#

C# 有没有可能做到';递归参数多态性&x27;在C中#,c#,generics,polymorphism,parametric-polymorphism,C#,Generics,Polymorphism,Parametric Polymorphism,所以我正在使用.NETCore,我正在制定一些需要扩展的数据契约,为此,我打算使用参数多态性,也就是泛型 现在,我的示例接口和类如下所示: public interface IEmailAttachment<TEmail, TAttachment> where TEmail : IEmail<TAttachment> where TAttachment : IEmailAttachment<IEmail<TAttachment>, TAttachment

所以我正在使用.NETCore,我正在制定一些需要扩展的数据契约,为此,我打算使用参数多态性,也就是泛型

现在,我的示例接口和类如下所示:

public interface IEmailAttachment<TEmail, TAttachment> where TEmail : IEmail<TAttachment> where TAttachment : IEmailAttachment<IEmail<TAttachment>, TAttachment>
{
    ...
    TEmail Email { get; set; }
    ...
}

public interface IEmail<TAttachment> where TAttachment : IEmailAttachment<IEmail<TAttachment>, TAttachment>
{
    ...
    IEnumerable<TAttachment> Attachments { get; set; }
    ...
}

public class DefaultEmail : IEmail<DefaultEmailAttachment>
{
    ...
    public IEnumerable<DefaultEmailAttachment> Attachments { get; set; }
    ...
}

public class DefaultEmailAttachment : IEmailAttachment<DefaultEmail, DefaultEmailAttachment>
{
    ...
    public DefaultEmail Email { get; set; }
    ...
}
public接口IEmailAttachment where TEmail:IEmail where tatachment:IEmailAttachment
{
...
TEmail电子邮件{get;set;}
...
}
公共接口IEmail,其中附件:IEmail附件
{
...
IEnumerable附件{get;set;}
...
}
公共类默认电子邮件:IEmail
{
...
公共IEnumerable附件{get;set;}
...
}
公共类DefaultEmailAttachment:IEmailAttachment
{
...
公共默认电子邮件{get;set;}
...
}
然而,这是行不通的。我得到这个错误:

对于DefaultEmail类:

“DefaultEmailAttachment”类型不能用作类型参数 泛型类型或方法“IEmail”中的“tatachment”。 不存在来自的隐式引用转换 “DefaultEmailAttachment”到 “电子邮件附件”

对于DefaultEmail附件:

“DefaultEmailAttachment”类型不能用作类型参数 泛型类型或方法“IEmailAttachment”中的“tatachment”。不存在来自的隐式引用转换 “DefaultEmailAttachment”到 “电子邮件附件”


我意识到这可能是因为我假设了一点,并且可能会循环使用类型参数,但是如果我遗漏了一些明显的可以使这项工作起作用的东西,请通知我,或者就如何工作提出另一个想法。

虽然这种合同在一开始似乎是个好主意,你不可避免地会遇到一连串(通常是无法解决的)问题。而且,这种结构非常不灵活。如何将不同类型的附件添加到电子邮件或将不同类型的邮件添加到电子邮件列表

您将如何为不同类型的附件动态创建电子邮件

虽然泛型在设计时是灵活的,但它不是动态的。这意味着在编译时必须知道具体类型

基本问题是:

  • 对于不同类型的附件,您真的需要不同类型的电子邮件吗
  • 为什么附件需要知道电子邮件的确切类型
  • 经典多态性不是足够且更灵活吗
在这两者之间还有一条路要走。通常,解决此类问题的方法是使用非泛型基接口(或类)和派生泛型类型:

public interface IAttachment
{
    IEmail Email { get; set; } // Only reference the non-generic base interface.
}

public interface IEmail
{
    // Only members not requiring a generic type parameter. 
}

public interface IEmail<TAttachment> where TAttachment : IAttachment
{
    ICollection<TAttachment> Attachments { get; set; }
}
公共接口连接
{
IEmail电子邮件{get;set;}//仅引用非通用基本接口。
}
公共接口电子邮件
{
//仅限不需要泛型类型参数的成员。
}
公共接口IEmail,其中TAttachment:IAttachment
{
ICollection附件{get;set;}
}
现在,您可以拥有不同类型电子邮件的列表

var mails = new List<IEmail>();
mails.Add(new EMail<SpecificAttatchment>());
mails.Add(new EMail<DefaultAttatchment>()); // or
mails.Add(new DefaultEmail());
var mails=newlist();
添加(新电子邮件());
mails.Add(新电子邮件());//或
mails.Add(新的DefaultEmail());

这稍微灵活一些,但在运行时访问不同
IEmail
类型的附件仍然存在问题。我不知道您试图用这种递归参数多态性解决什么类型的问题,但我只会使用非泛型
IAttachment
IEmail
接口。如果仍然需要泛型类型参数,请尝试避免递归。

虽然这种契约在一开始似乎是个好主意,但您不可避免地会遇到一连串(通常无法解决的)问题。而且,这种结构非常不灵活。如何将不同类型的附件添加到电子邮件或将不同类型的邮件添加到电子邮件列表

您将如何为不同类型的附件动态创建电子邮件

虽然泛型在设计时是灵活的,但它不是动态的。这意味着在编译时必须知道具体类型

基本问题是:

  • 对于不同类型的附件,您真的需要不同类型的电子邮件吗
  • 为什么附件需要知道电子邮件的确切类型
  • 经典多态性不是足够且更灵活吗
在这两者之间还有一条路要走。通常,解决此类问题的方法是使用非泛型基接口(或类)和派生泛型类型:

public interface IAttachment
{
    IEmail Email { get; set; } // Only reference the non-generic base interface.
}

public interface IEmail
{
    // Only members not requiring a generic type parameter. 
}

public interface IEmail<TAttachment> where TAttachment : IAttachment
{
    ICollection<TAttachment> Attachments { get; set; }
}
公共接口连接
{
IEmail电子邮件{get;set;}//仅引用非通用基本接口。
}
公共接口电子邮件
{
//仅限不需要泛型类型参数的成员。
}
公共接口IEmail,其中TAttachment:IAttachment
{
ICollection附件{get;set;}
}
现在,您可以拥有不同类型电子邮件的列表

var mails = new List<IEmail>();
mails.Add(new EMail<SpecificAttatchment>());
mails.Add(new EMail<DefaultAttatchment>()); // or
mails.Add(new DefaultEmail());
var mails=newlist();
添加(新电子邮件());
mails.Add(新电子邮件());//或
mails.Add(新的DefaultEmail());

这稍微灵活一些,但在运行时访问不同
IEmail
类型的附件仍然存在问题。我不知道您试图用这种递归参数多态性解决什么类型的问题,但我只会使用非泛型
IAttachment
IEmail
接口。如果仍然需要泛型类型参数,请尝试避免递归。

Olivier提出了一些好的观点。我同意他的所有观点,并且不会特别推荐这种方法,因为理解这些限制是多么困难。然而,是的,它是可以实现的。如果两个类具有相同的参数和相同的约束,则更容易理解:

public interface IEmailAttachment<TEmail, TAttachment> where TEmail : IEmail<TEmail, TAttachment> where TAttachment : IEmailAttachment<TEmail, TAttachment>
{
    TEmail Email { get; set; }
}

public interface IEmail<TEmail, TAttachment> where TEmail : IEmail<TEmail, TAttachment> where TAttachment : IEmailAttachment<TEmail, TAttachment>
{
    IEnumerable<TAttachment> Attachments { get; set; }
}

public class DefaultEmail : IEmail<DefaultEmail, DefaultEmailAttachment>
{
    public IEnumerable<DefaultEmailAttachment> Attachments { get; set; }
}

public class DefaultEmailAttachment : IEmailAttachment<DefaultEmail, DefaultEmailAttachment>
{
    public DefaultEmail Email { get; set; }
}
public接口IEmailAttachment where TEmail:IEmail where tatachment:IEmailAttachment
{
TEmail电子邮件{get;set;}
}
公共接口IEmail where TEmail:IEmail where TAttachment:IEmail附件
{
伊努梅拉布尔