草庐IT

c# - 继承的通用类型统一

coder 2024-05-21 原文

对于这样的场景:

public interface IAnimal
{

}

public interface IGiraffe : IAnimal
{

}

public interface IQuestionableCollection : IEnumerable<IAnimal>
{
    void SomeAction();
}

public interface IQuestionableCollection<out T> : IQuestionableCollection, IEnumerable<T>
    where T : IAnimal
{

}

public class QuestionableCollection<T> : IQuestionableCollection<T>
    where T:IAnimal
{
    // Implementation... 
}

编译器会产生一个错误:

'IQuestionableCollection<T>' cannot implement both 'System.Collections.Generic.IEnumerable<IAnimal>' and 'System.Collections.Generic.IEnumerable<T>' because they may unify for some type parameter substitutions

这是有道理的,这两个接口(interface)之间确实存在歧义,除非使用类型约束,否则 C# 无法解决,正如@ericlippert 解释的那样,它不符合语言规范 here .

我的问题是我应该如何在这里实现相同的效果?

看来我应该能够表达集合对于基本接口(interface)是可枚举的。 (我想提供一组可以在不知 Prop 体类型的情况下使用的方法,以及它使一些 API/反射代码更清晰,所以我想将基本集合保持为非泛型(如果有的话)可能。否则,将不需要两个接口(interface)。)

我能想到的唯一编译实现是这样的:

public interface IQuestionableCollectionBase
{
    void SomeAction();
}

public interface IQuestionableCollection : IQuestionableCollectionBase, IEnumerable<IAnimal>
{

}

public interface IQuestionableCollection<out T> : IQuestionableCollectionBase, IEnumerable<T>
    where T : IAnimal
{

}

public class QuestionableCollectionBase<T> : IQuestionableCollection
    where T : IAnimal
{
    protected List<T> _items = new List<T>();

    public void SomeAction() { }

    IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); }
    IEnumerator<IAnimal> IEnumerable<IAnimal>.GetEnumerator() { return ((IEnumerable<IAnimal>)_items).GetEnumerator(); }
}

public class QuestionableCollection<T> : QuestionableCollectionBase<T>, IQuestionableCollection<T>
    where T : IAnimal
{
    public IEnumerator<T> GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); }
}

请注意,我必须将我想在两个接口(interface)上使用的任何方法移动到一个基本方法,并且类本身有两个级别的实现 - 这似乎我在这里跳过了足够多的箍一定是少了什么……

这应该如何实现?

最佳答案

最简单的解决方法是将 IEnumerables 从“is-a”更改为“has-a”,如下所示:

public interface IAnimal { }
public interface IGiraffe : IAnimal { }

public interface IQuestionableCollection
{
    IEnumerable<IAnimal> Animals { get; }
    void SomeAction();
}

public interface IQuestionableCollection<out T> : IQuestionableCollection
    where T : IAnimal
{
    new IEnumerable<T> Animals { get; }
}

public class QuestionableCollection<T> : IQuestionableCollection<T>
    where T : IAnimal, new()
{
    private readonly List<T> list = new List<T>();

    public IEnumerable<T> Animals
    {
        get { return list; }
    }

    IEnumerable<IAnimal> IQuestionableCollection.Animals
    {
        get { return (IEnumerable<IAnimal>)list; }
    }

    public void SomeAction()
    {
        list.Add(new T());
    }
}

class Giraffe : IGiraffe { }

[TestMethod]
public void test()
{
    var c = new QuestionableCollection<Giraffe>();
    IQuestionableCollection<Giraffe> i = c;
    IQuestionableCollection<IGiraffe> i2 = i;

    Assert.AreEqual(0, c.Animals.Count());
    Assert.AreEqual(0, i.Animals.Count());
    c.SomeAction();
    i.SomeAction();
    Assert.AreEqual(2, c.Animals.Count());
    Assert.AreEqual(2, i.Animals.Count());
}

请注意,您可以避免 QuestionableCollection<T> 中的转换如果你添加 where T : class约束条件。

关于c# - 继承的通用类型统一,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29907762/

有关c# - 继承的通用类型统一的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  3. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  4. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  5. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  6. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  7. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  10. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

随机推荐