【问题标题】:Generic interfaces and inheritance in .NET.NET 中的通用接口和继承
【发布时间】:2022-12-12 19:45:43
【问题描述】:

我有以下场景,涉及如下几个接口

    internal interface ITranslation
    {
        string LanguageCode { get; set; }
        string Title { get; set; }
    }

任何包含翻译的对象都将实现 ITranslation 接口。其中一些对象也可以有同义词,所以我有另一个接口

    internal interface ITranslationWithSynonmys : ITranslation
    {
        IList<string> Synonyms { get; set; }
    }

下一步我已经为任何有翻译并且可以翻译成不同语言的对象定义了ITranslatable&lt;T&gt;接口

    internal interface ITranslatable<T> where T : ITranslation
    {
        IList<T> Translations { get; set; }
    }

而当涉及同义词时,ITranslatableWithSynonyms&lt;T&gt; 看起来像这样

    internal interface ITranslatableWithSynonyms<T> : ITranslatable<T> where T : ITranslationWithSynonmys
    {
        IList<T> SynonymTanslations { get; set; }
    }

ITranslationITranslationWithSynonmys 的具体实现是

    internal class BaseTranslation : ITranslation
    {
        public string Title { get; set; }
        public string LanguageCode { get; set; }
    }

    internal class BaseTranslationWithSynonmys : ITranslationWithSynonmys
    {
        public IList<string> Synonyms { get; set; }
        public string LanguageCode { get; set; }
        public string Title { get; set; }
    }

而可以翻译的实体将是

    internal class TranslatableEntity : ITranslatable<ITranslation>
    {
        public IList<ITranslation> Translations { get; set; }
    }

如果它有同义词

    internal class TranslatableWithSynonymsEntity : ITranslatableWithSynonyms<ITranslationWithSynonmys>
    {
        public IList<ITranslationWithSynonmys> SynonymTanslations { get; set; }
        public IList<ITranslationWithSynonmys> Translations { get; set; }
    }

接下来,我正在创建一个可以翻译任何实现ITranslatable&lt;T&gt; 的对象的服务,我将其定义为

    internal class TranslationService
    {
        internal string Translate(ITranslatable<ITranslation> translatable, string languageCode)
        {
            // It will iterate through the Translations list to find the correct translation
            return string.Empty;
        }
    }

现在,当我尝试使用该服务时,我正在写

var translationService = new TranslationService();
var translatableEntity = new TranslatableEntity();
var translatableWithSynonymsEntity = new TranslatableWithSynonymsEntity();
string x = translationService.Translate(translatableEntity, "en");
string y = translationService.Translate(translatableWithSynonymsEntity, "en");

最后一行 translationService.Translate(translatableWithSynonymsEntity, "en") 编译失败错误 CS1503:参数 1:无法从“TestInheritance.TranslatableWithSynonymsEntity”转换为“TestInheritance.ITranslatable<TestInheritance.ITranslation>”

TranslatableWithSynonymsEntity确实没有实现ITranslatable&lt;ITranslation&gt;,但它实现了ITranslatableWithSynonyms&lt;ITranslationWithSynonmys&gt;ITranslatableWithSynonyms&lt;T&gt;继承自ITranslatable&lt;T&gt;ITranslationWithSynonmys继承自ITranslation

我可以通过让 TranslatableWithSynonymsEntity 实现 ITranslatableWithSynonyms&lt;ITranslationWithSynonmys&gt;ITranslatable&lt;ITranslation&gt; 来编译代码,但这意味着管理两个列表并且它看起来并不干净的.

    internal class TranslatableWithSynonymsEntity : ITranslatableWithSynonyms<ITranslationWithSynonmys>, ITranslatable<ITranslation>
    {
        public IList<ITranslationWithSynonmys> SynonymTanslations { get; set; }
        public IList<ITranslationWithSynonmys> Translations { get; set; }
        IList<ITranslation> ITranslatable<ITranslation>.Translations { get; set; }
    }

有没有办法避免这种情况?还是我采取了错误的方法?

谢谢

【问题讨论】:

  • 看起来你可以完全放弃泛型——不清楚你在这里需要它们做什么?
  • 我需要泛型,因为 ITranslatable 可以有一个 ITranslation 列表或任何继承自 ITranslation 的接口。我不希望它总是返回 ITranslatable。正如您在 TranslatableWithSynonymsEntity 的情况下看到的那样,它返回 IList<ITranslationWithSynonmys>
  • 现在,由于您的 ITranslatableWithSynonyms 和 ITranslatable 接口指定了一些 IList&lt;T&gt; Something {get;set;} 属性,因此不可能使它们协变。因此,您要么必须找到一种方法来避免使用 setter 和一些非协变 interface<T> 类型作为属性的返回类型(不允许使接口​​协变)的属性,要么您必须找到一个不同的类/界面设计完全...
  • @MySkullCaveIsADarkPlace 基于stackoverflow.com/questions/5832094/covariance-and-ilist,一种选择是使用 IReadOnlyList<out T> 代替 IList<T>。也许我可以适应

标签: c# generics inheritance interface


【解决方案1】:

泛型参数默认是不变的,在方法@​​987654321@中你希望类型是&lt;ITranslation&gt;,所以你必须提供一个泛型参数(或其父代)正好是&lt;ITranslation&gt;的类型。

在您的示例中,您不能简单地将参数标记为协变,因为它包含一个同时具有 getter 和 setter 的属性。

既然问题是泛型参数,解决问题,不指定一个,其实你已经从ITranslation约束了泛型参数

interface ITranslatable<T> where T : ITranslation

方法(或类)只需要用相同的约束声明。

internal string Translate<T>(ITranslatable<T> translatable, string languageCode)
     where T : ITranslation

【讨论】:

    猜你喜欢
    • 2010-09-17
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2015-10-03
    • 2010-09-21
    相关资源
    最近更新 更多