【问题标题】:Generic Methods that overwrite parameters without reference?在没有引用的情况下覆盖参数的通用方法?
【发布时间】:2015-11-19 17:59:17
【问题描述】:

好吧,这可能是一个非常愚蠢的问题,但无论如何我都会冒我的代表的风险。我对编程很陌生,所以放轻松吧;) 所以当我遇到一些我不太明白的事情时,我才进入 TCP。 具体来说:

int length = Socket.Receive(MyByteArray);

据我了解,此方法返回接收到的数据的长度将接收到的数据写入我的字节数组。那么它如何在没有我告诉它的情况下写入我的字节数组呢?经过一些研究,我了解到您可以使用引用来做这种事情,但这种方法不需要“ref MyByteArray”,这让我感到困惑。这是一种不同的方法还是方法内部发生了什么(duh)?

在此先感谢你这个非常棒的人。

【问题讨论】:

  • 对引用类型和值类型做一些研究。数组是引用类型,因此当您将一个传递给函数时,它具有对实际对象的 reference 并且可以更改其属性。
  • 你告诉它通过将你的字节数组传递给它来写入你的字节数组。
  • 不解释为什么,很容易自己验证它有效:ideone.com/HrLDZ3
  • 数组是引用类型,而不是值类型(即使它是值类型的数组),所以如果数组是预先分配的,则不需要使用ref 传递。跨度>

标签: c# ref


【解决方案1】:

引用类型传递给方法有时对于开发人员来说是一件不直观的事情。考虑以下两段代码(均未使用ref 关键字):

void Method1(SomeType myObj)
{
    myObj = new SomeType();
}

void Method2(SomeType myObj)
{
    myObj.SomeProperty = 1;
}

第一种方法没有副作用。引用类型被传递到方法中,由于缺乏更好的术语,该方法基本上是指向内存中对象的“指针”(本身按值传递)。如果将变量设置为内存中的 new 对象,则原始对象保持不变。然后内存中有两个对象。 (尽管一旦方法结束,新的就会消失,因为没有人使用它。)

second 方法,但是,确实 有副作用。它对内存中的对象使用相同的引用,但它修改了对象本身。因此,在调用方法后检查对象的任何内容都会看到该修改。


大概,Socket.Receive() 做了类似于上面第二种方法的事情。它使用引用来修改对象。


为了说明ref 关键字将如何改变这一点:

void Method3(ref SomeType myObj)
{
    myObj = new SomeType();
}

这个场景中,还有一个副作用。任何调用该方法然后检查它发送给该方法的对象的代码都会看到该对象已被新对象替换。在这种情况下,没有第二个“指针”指向内存中的同一位置。该方法使用了调用代码使用的实际指针

【讨论】:

  • 为了清楚起见,为什么在修改原始对象时不总是使用 ref ?
  • @ThatBrianDude:我想你可以。老实说,像Socket.Receive() 这样的方法在这方面让我很困扰。对于我传递给要修改的方法的东西,我个人觉得它出乎意料。遵循最小惊讶原则等等。对于发生这种情况的框架中的任何给定方法,我怀疑它的来源以及他们为什么这样做的历史,现在它就是这样,他们不能引入重大变化。但是我们今天写的任何东西都不应该像那样修改对象。
  • @David 你必须了解数组的来源,它继承自class Array。话虽如此,一个类将通过引用传递;)。考虑这是一个 C++ 指针,将引用传递给将要写入数据的数组是有意义的......
  • @PhilippeParé:您的意思是将该评论发送给其他用户吗?我对引用类型相当熟悉...
  • @PhilippeParé:我指的是个人喜好问题。我完全了解引用类型是如何工作的。我想说的是,在我看来,将某些东西传递给一个方法并对其进行变异(至少没有ref 关键字)是不直观的。我了解如何实现这一点的技术原因。我只是不认为这是一个好的设计选择。代码读起来不太干净,它迫使开发人员暂时停止思路并考虑其他事情。不管其他事情多么简单,它都会破坏注意力。
猜你喜欢
  • 2019-06-29
  • 1970-01-01
  • 1970-01-01
  • 2014-01-20
  • 1970-01-01
  • 2018-05-03
  • 1970-01-01
  • 1970-01-01
  • 2012-11-10
相关资源
最近更新 更多