【问题标题】:Pass class instance without reference传递类实例而不引用
【发布时间】:2012-06-28 13:51:48
【问题描述】:

我有一个关于是否通过 ref 传递一些实例的问题:这是我的问题:

案例 1:简单的 var,如 int:

private void button2_Click(object sender, EventArgs e)
{
    int nTest = 10;

    testInt(nTest);
    MessageBox.Show(nTest.ToString());
    // this message show me 10

    testIntRef(ref nTest);
    MessageBox.Show(nTest.ToString());
    // this message show me 11
}

private void testInt(int nn)
{
    nn++;
}

private void testIntRef(ref int nn)
{
    nn++;
}

这正是我的想法,如果我使用ref,参数是通过引用传递的,所以如果改变了,当我退出函数时,值改变了......

案例 2:类:

// simple class to understand the reference..
public class cTest
{
    int nTest;
    public cTest()
    {
        setTest(0);
    }

    public void setTest(int n)
    {
        nTest = n;
    }

    public int getTest()
    {
        return nTest;
    }
}

// my main code
private void button3_Click(object sender, EventArgs e)
{
    cTest tt = new cTest();
    tt.setTest(2);

    testClass(tt);

    // I expect that the message shows me 2, 'cause testClass
    // doesn't have (ref cTest test)
    MessageBox.Show(tt.getTest().ToString());
}

private void testClass(cTest test)
{
    test.setTest(55);
}

并且,正如代码评论中所写,我没有通过我的 cTest 作为参考,但结果是一样的,消息显示我是 55 而不是 2..

如何在没有引用的情况下通过类?

【问题讨论】:

    标签: c# reference pass-by-reference ref


    【解决方案1】:

    如果你只是想确保一个方法不能修改一个参数,那么你可以创建一个只读基类:

    public abstract class ReadOnlyUser
    {
        public string GetName() { ... }
    }
    
    public class User : ReadOnlyUser
    {
        public void SetName(string name) { ... }
    }
    

    那你可以把方法写成方法体不能误修改参数:

    public void Register(ReadOnlyUser user)
    {
        string name = user.GetName();
        user.SetName("John"); // doesn't compile
    }
    

    当然,您可以使用User 类的实例调用此方法:

    var user = new User(...);
    Register(user);
    

    你也可以实现一个只读接口:

    public interface IReadOnlyUser
    {
        string GetName();
    }
    
    public interface IUser : IReadOnlyUser
    {
        void SetName(string name);
    }
    
    public class User : IUser
    {
        public string GetName() { ... }
        public void SetName(string name) { ... }
    }
    
    public void Register(IReadOnlyUser user)
    {
        string name = user.GetName();
        user.SetName("John"); // doesn't compile
    }
    

    【讨论】:

      【解决方案2】:

      如何在没有引用的情况下通过类?

      你不能。

      您可以克隆该实例并发送它,但它仍将由 ref 发送...

      • 类 - 引用类型
      • 结构 - 值类型。

      阅读:

      引用Jon Skeet C# in depth second edition:

      误区 #3:“对象在 C# 中默认通过引用传递”

      这可能是传播最广的神话。再次,制作这个的人 声称经常(尽管不总是)知道 C# 的实际行为,但他们不知道 “通过引用传递”的真正含义。不幸的是,这让那些 知道这意味着什么。引用传递的正式定义比较复杂, 涉及 l 值和类似的计算机科学术语,但重要的是 问题是如果你通过引用传递一个变量,你调用的方法可以改变 通过更改其参数值来更改调用者变量的值。现在请记住, 引用类型变量的值是引用,而不是对象本身。你可以改变 参数引用的对象的内容,而参数本身不存在 通过引用传递。 例如,下面的方法改变了 StringBuilder 对象,但调用者的表达式仍将引用 和以前一样的对象:

      void AppendHello(StringBuilder builder)
      {
          builder.Append("hello");
      }
      

      调用此方法时,参数值(对 StringBuilder 的引用)为 按值传递。如果我要更改 builder 变量的值 方法——例如,使用语句 builder = null;——这种改变不会是 被调用者看到,与神话相反

      深入了解 C# 值类型和引用类型第 46 页

      【讨论】:

      • @ghiboz。另一件事,如果你需要的话,请确保你创建一个deep clone
      • 感谢您的链接,所以,明确地说,如果我使用一个类,如果我写 private void testClass(cTest test)private void testClass(ref cTest test) 是同一件事..
      • @ghiboz: 如果通过 ref 传递参数,你可以使用 st 像:test = new cTest(),并且参数将是一个新对象,而如果没有 ref 传递,则测试将是 un-如果分配则更改: test = new cTest();
      • @ghiboz:如果是这样,请调查编译器如何存储变量(原始数据类型与对象数据类型,堆栈内存与堆内存)。您可能会自己发现答案
      【解决方案3】:

      如果你想要这样的东西,你想使用 struts 而不是类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-24
        相关资源
        最近更新 更多