c#:在类中保留构造函数的ref参数

时间:2011-03-10 14:35:17

标签: c# winforms reference

基本上我希望能够在类的实例中引用变量,但我希望引用成为类变量,所以我不需要在类的内部作为参数发送它

代码:

int num = 0;
myClass(num);
print num; // output is 0 but i'd like it to be 10 :)
class myClass
{
    private int classNumber;
    myClass(ref int number)
    {
        print number; //output is 0

        // id like this to be a reference to the refenrence
        classNumber = number;

        DoSomething();
    }
    public void DoSomething()
    {
        ClassNumber = 10;
    }
}

为什么我要问这是因为我正在使用winforms并且有一个主表单将一个类的实例发送到一个新表单,该表单应该编辑该类并将其发回...现在我使用Form.ShowDialog ()避免用户在新表单中编辑时使用主表单,然后从新表单中获取数据

editForm edtfrm = new editForm(ref instanceOfClass);
edtfrm.showDialog();
//grab the instance back
instanceOfClass = edtfrm.editedClass;

我该如何解决这个问题?我不喜欢这个解决方案

6 个答案:

答案 0 :(得分:14)

  

我希望能够在类的实例中引用变量,但我希望引用成为类变量,所以我不需要在类的内部作为参数发送它/ p>

那么你将不得不忍受失望。 CLR类型系统明确禁止将变量的引用存储为类的成员。 CLR允许引用变量

  • 作为参数传递给方法,对应于形式参数或'this'
  • 存储为本地人
  • 作为方法返回值
  • 返回

允许在数组,字段等中存储。基本上,“在堆上”的任何东西都无法保留参考。

C#公开了第一个特性:将变量作为方法参数引用。它没有公开其他两个功能(虽然我已经编写了一个C#的实验版本,它的功能非常好。)

请注意,C#不允许您在需要堆存储ref的上下文中使用ref - 例如,ref参数是lambda的封闭外部变量。有一些罕见的情况,编译器确实允许看起来像ref的长期存储,并使用copy-in-copy-out语义来模拟ref,但最好甚至不去那里。

为什么CLR有此限制?考虑它的正确方法是有两种存储:长期和短期,通常称为“堆”和“堆栈”。但数据结构的形状无关紧要;相关的是寿命的长短。变量具有存储位置;这就是变量。如果你可以在长期存储中保留一个从短期存储分配的变量的参考,那么长期存储会保留一个生命周期较短的内容,因此在访问变量时可能会崩溃并死亡死后。

显然有很多方法可以解决这个问题。例如,CLR团队可能选择将参考资料用于短期存储是非法的,并允许在长期存储中存储ref。但那意味着你不能把refs带到局部变量或参数,你想把它放在短期存储中,因为它们的生命很短暂。

CLR团队实际选择的方式是禁止长期存储任何参考。与任何设计决策一样,这是与竞争目标进行许多权衡的结果。

答案 1 :(得分:2)

你想要做什么并不是一个好主意,我会将修改后的对象公开为类的属性,如下所示:

public class ClassContructorReference
{
    static void Main(string[] args)
    {
        object var = new object();
        MyClass myClass = new MyClass(var);
        StringBuilder mySb = myClass.Instance as StringBuilder;
        Console.WriteLine(mySb.ToString());
    }
}

public class MyClass
{
    public object Instance {get;set;}

    public MyClass(object var)
    {
        this.Instance = var;
        DoSomething();
    }

    private void DoSomething()
    {
        this.Instance = new StringBuilder("Hello");
    }
}

答案 2 :(得分:1)

当然你的测试代码不会工作,因为它是一个原始类型。但你的第二个代码将起作用,因为它是一个引用类型。(甚至不需要'ref')不需要重新分配实例。

public class Second
{
    public First f;

    public Second(First f)
    {
        this.f= f;
    }

    public void change()
    {
        this.f.Name = "PUli";
    }
}
public class First
{
    private string _name;

    public First()
    {
        Name = "SUli";
    }

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}
class Program
{
    static void Main(String[] args)
    {
        First f = new First();
        Second sec = new Second(f);
        Console.WriteLine(f.Name);
        sec.change();
        Console.WriteLine(f.Name);
    }
}

输出: -

SUli

普利

答案 3 :(得分:0)

创建一个包含您的号码作为属性的类,并将其传递给您的逻辑。该课程将代表您的“模特”。

答案 4 :(得分:0)

您无法保存ref参数,ref不是参考,只是alias。如果你有:

public void Stuff (ref int i)
{
  i = 2;
}

并称之为:

int s = 1;
Stuff(ref s);

ref表示“使我成为s的别名并将更改传播给它”。一旦离开方法的范围,该别名就消失了。很明显,Eric Lippert在他的blog上开始了一个关于这个问题的系列文章。

您应该创建一个类并在逻辑中使用它。 GUI不应该操纵值,只应该操作后端。

答案 5 :(得分:0)

这里有几件事。 首先,在您的构造函数中,您可能想要

DoSomething();     
number=classnumber;

而不是

classnumber=number;

第二,尝试

myClass(ref num);

而不是

myClass(num);