通过引用传递对象与cs1690之间的冲突

时间:2015-07-10 10:24:03

标签: c# object ref

此代码已更新。 Robot.cs:

 struct state systemcheck()
 {
 state stateInfo = new state();
 public double x,y,z; 
 }

Main.cs:

public state stateInfo;
private readonly Sub cpnew;
public Main()
{
InitializeComponent();
cpnew = new Sub(this);
}

Sub.cs:

public state systinfo;
private readonly Main main;
public Sub(Main main)
{
InitializeComponent();     
this.main = main;
systinfo = this.main.stateInfo; 
} 

此处,systinfo.X提供空值。但mainfrm.stateInfo.X提供了正确的值,但会引发按引用引用的类警告。 初始化systinfo的正确方法是什么? state的值是从外部连接的机器人获得的。

1 个答案:

答案 0 :(得分:2)

你提出的一件好事 - 记得要始终遵循警告,除非你完全知道自己在做什么。在这种情况下,你肯定会知道你在做什么。

Formclass - 所有类都是.NET中的引用类型。这有几个含义,其中一个在这里非常相关 - 它们始终通过引用传递。换句话说,当您使用Main main作为参数时,您已经传递了一个引用(类似于在C中传递指向Main的指针)。

使用ref,您将参考传递给参考。这允许您从方法内部修改外部引用。这不是你想要的 - 作为一个简单的例子,它可以让你写一个增量方法:

public void Increment(ref int value)
{
  value = value + 1;
}

如果您没有使用ref,则只会修改value的本地值。使用ref,它会修改调用者中的本地

在您的情况下,正确的代码将更接近

public state stateInfo;
private readonly Sub cpnew;
public Main()
{
    InitializeComponent();

    cpnew = new Sub(this);
}

窗体2:

public state systinfo;
private readonly Main main;
public Sub(Main main)
{
    InitializeComponent();      
    this.main = main;
    systinfo = mainfrm.stateInfo; 
} 

那么,警告告诉你什么? Form继承自MarshalByRefObject。这意味着您可能实际上并未传递真实的Form对象 - 完全有可能只有代理到远程计算机上的Form,例。这意味着该类型上的所有调用都将通过代理自动编组,在实际实例上执行,并返回结果。由于statestruct(我打赌它是因为你不了解C#' struct和C&#之间的区别39; s struct),它是一个值类型 - 如果你确实持有代理而不是真实实例,这将导致运行时异常。

要绕过警告,您可以先将state复制到本地 - 这样可以确保安全(更重要的是,显而易见)。

在从C ++切换到C#时,您可以使用陷阱很多 - 它们在表面上看起来很相似,但是很多差异。尝试在实际操作之前查看一下您尝试使用的内容 - 例如,查找ref关键字会明显表明您正在指向指针,并且查找structclass将告诉您它们的行为与C ++完全不同。小心点。

用C#惯用语编码变得更加严重。例如,您通常在需要它们的地方创建子表单和对话框,而不是在构造函数中创建实例并在需要时重用它。当然,循环引用通常是一个糟糕的想法 - 它是增加代码复杂性的好方法,它使调试和测试更加昂贵。进一步的重构也会因循环引用而受到更多伤害。