【问题标题】:Return Type of Method Not Matching Type of Variable Returned, But Still Works方法的返回类型与返回的变量类型不匹配,但仍然有效
【发布时间】:2014-08-26 18:07:37
【问题描述】:

我正试图围绕 C# 中的所有列表接口(IEnumarable、IReadOnlyCollection)等。作为其中的一部分,我意识到我并不真正理解为什么下面的代码有效。毕竟,该方法有一个 IReadOnlyCollection 作为返回类型,但返回的变量是 Array (float[]) 类型。我意识到 Array 实现了 IReadOnlyCollection 接口,但我不知道它是如何从一个转换到另一个的。它是在后台以某种方式完成的吗?

private readonly float[] _location;

public Player()
{
    _location = new float[3];
}

public IReadOnlyCollection<float> Location
{
    get
    {
        _location[0] = Worker.Elements["lbXCoordinate"].Value;
        _location[1] = Worker.Elements["lbYCoordinate"].Value;
        _location[2] = Worker.Elements["lbZCoordinate"].Value;

        return _location;
    }
}

【问题讨论】:

  • 没有转换 - 返回的 IReadOnlyCollection&lt;float&gt; 引用将是对数组本身的引用。 (不,你不应该像这样实现属性......)
  • @JonSkeet Jon,感谢您的回复。我试图确保消费者不会篡改 Property 的结果(以前它曾经返回一个简单的 float[],但我意识到可以写入 Array)。我在 get 访问器中编写变量的事实是为了确保每当有人请求它时,他们都会获得更新的值。请参阅我的另一篇文章:stackoverflow.com/questions/25506487/…。如果您能解释我应该做什么,我将不胜感激。谢谢一百万!
  • 好吧,调用者总是可以转换回数组类型。我建议在每次调用时创建一个 new 数组......或者理想情况下,创建一个具有三个属性的单独结构,而不是一个集合。
  • @JonSkeet 有趣的是,您会这么说,因为在将 float[] 作为返回类型之前,我将 struct Waypoint 作为返回类型。但是,我的程序每秒可能不止一次地调用此访问器,因此每次创建一个新的 Waypoint(或新数组)实例都会损害性能,对吗?我的 Waypoint 结构相当大。我链接到的帖子解释得更好。
  • “每秒不止一次”几乎没有任何意义。你知道你每秒能做多​​少吗?但从根本上说,一个只有 3 个 float 值的结构应该没问题 - 它只有 12 个字节,甚至不会在堆上。当然,这比返回一个数组要好,这样每次调用 Location 都会返回相同的引用,可能会为其他所有人更改数组...

标签: c# collections interface


【解决方案1】:

一个对象可以被隐式地转换成它的类实现的任何一个接口;但是,没有发生 转换 - 正如 Jon Skeet 在评论中指出的那样,它是返回的原始数组。对于调用者,它将被“伪装”为IReadOnlyCollection&lt;float&gt;,并且调用者理想情况下只会对它执行来自IReadOnlyCollection&lt;float&gt; 的操作。但是,如果调用者知道或怀疑实际类型,则调用者可能决定将其转换回float[],并且您的对象的封装将被破坏。 (不过,这对调用者来说是有风险的,因为如果您在某些时候将实际类型更改为 List&lt;float&gt;,则转换为 float[] 的代码将中断。)为了确保封装,返回的对象必须是自身保护其内容,因此您确实应该创建一个带有私有(或没有)设置器的类/结构。然后,您的代码也将变得更具可读性和自我记录性。

【讨论】:

    【解决方案2】:

    上面的代码有效,因为IReadOnlyCollection接口实现了IEnumerable,而Array抽象类也实现了IEnumerable接口。因此,当您为 IReadOnlyCollection 返回类型的方法返回浮点数组时,会在内部对 IEnumerable 进行向上转换。

    我希望这就是你要找的。​​p>

    【讨论】:

    • 难道不是因为 Array 实现了该接口,而是将 Array 向上转换为 IReadOnlyCollection?当我查看名为 Location 的变量的类型时,它们的类型是 IReadOnlyCollection,而不是 IEnumerable。
    【解决方案3】:

    不,Array 没有实现 IReadOnlyCollection,请参考以下链接: http://msdn.microsoft.com/en-IN/library/system.array(v=vs.110).aspx

    IReadOnlyCollection 也实现了相同的接口 IEnumerable,请参考以下链接: http://msdn.microsoft.com/en-us/library/hh881542(v=vs.110).aspx

    现在,当您尝试为类型为 IReadOnlyCollection 的方法返回一个数组时,这是对其基本类型 IEnumerable 的类型安全转换。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-30
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多