此代码已更新。 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
的值是从外部连接的机器人获得的。
答案 0 :(得分:2)
你提出的一件好事 - 记得要始终遵循警告,除非你完全知道自己在做什么。在这种情况下,你肯定会不知道你在做什么。
Form
是class
- 所有类都是.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
,例。这意味着该类型上的所有调用都将通过代理自动编组,在实际实例上执行,并返回结果。由于state
是struct
(我打赌它是因为你不了解C#' struct
和C&#之间的区别39; s struct
),它是一个值类型 - 如果你确实持有代理而不是真实实例,这将导致运行时异常。
要绕过警告,您可以先将state
复制到本地 - 这样可以确保安全(更重要的是,显而易见)。
在从C ++切换到C#时,您可以使用陷阱很多 - 它们在表面上看起来很相似,但是很多差异。尝试在实际操作之前查看一下您尝试使用的内容 - 例如,查找ref
关键字会明显表明您正在指向指针,并且查找struct
和class
将告诉您它们的行为与C ++完全不同。小心点。
用C#惯用语编码变得更加严重。例如,您通常在需要它们的地方创建子表单和对话框,而不是在构造函数中创建实例并在需要时重用它。当然,循环引用通常是一个糟糕的想法 - 它是增加代码复杂性的好方法,它使调试和测试更加昂贵。进一步的重构也会因循环引用而受到更多伤害。