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

Conflict between passing object by reference and cs1690

此代码已更新。 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 提供了正确的值,但抛出 marshal-by-reference class 警告。 初始化 systinfo 的正确方法是什么? state 的值是从外部连接的机器人获得的。

你问的好 - 请记住始终遵循警告,除非你完全知道你在做什么。在这种情况下,您肯定不知道自己在做什么。

Form 是一个 class - 而所有 类 都是 .NET 中的引用类型。这有几个含义,其中之一与这里高度相关 - 它们 always 通过引用传递。换句话说,当您使用 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 对象——例如,您完全有可能只有一个 proxy 到远程计算机上的 Form .这意味着对该类型的所有调用都通过代理自动编组,在 actual 实例上执行,并返回结果。由于 statestruct(我敢打赌这是因为您不了解 C# 的 struct 和 C 的 struct 之间的区别),它是一个值类型 -如果您确实持有代理而不是真实实例,这将导致运行时异常。

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

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

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