通过引用传递对象和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 实例上执行,并返回结果。由于 state
是 struct
(我敢打赌这是因为您不了解 C# 的 struct
和 C 的 struct
之间的区别),它是一个值类型 -如果您确实持有代理而不是真实实例,这将导致运行时异常。
要绕过警告,您可以先将 state
复制到本地 - 这样可以确保安全(更重要的是,明显)。
从 C++ 切换到 C# 时,您可能会陷入 很多 个陷阱 - 它们表面上看起来很相似,但实际上 很多 差异。尝试在实际使用之前查找一下您要尝试使用的任何内容 - 例如,查找 ref
关键字会很明显地表明您正在制作指向指针的指针,并查找 struct
和 class
会告诉您它们的行为与 C++ 完全不同。小心点。
C# 编码地道变得更加严肃。例如,您通常会在需要的地方创建子表单和对话框,而不是在构造函数中创建实例并在需要时重新使用它。当然,循环引用通常是一个糟糕的想法——它是增加代码复杂性的好方法,它使调试和测试更加昂贵。进一步的重构也会对循环引用造成更大的伤害。
此代码已更新。 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 实例上执行,并返回结果。由于 state
是 struct
(我敢打赌这是因为您不了解 C# 的 struct
和 C 的 struct
之间的区别),它是一个值类型 -如果您确实持有代理而不是真实实例,这将导致运行时异常。
要绕过警告,您可以先将 state
复制到本地 - 这样可以确保安全(更重要的是,明显)。
从 C++ 切换到 C# 时,您可能会陷入 很多 个陷阱 - 它们表面上看起来很相似,但实际上 很多 差异。尝试在实际使用之前查找一下您要尝试使用的任何内容 - 例如,查找 ref
关键字会很明显地表明您正在制作指向指针的指针,并查找 struct
和 class
会告诉您它们的行为与 C++ 完全不同。小心点。
C# 编码地道变得更加严肃。例如,您通常会在需要的地方创建子表单和对话框,而不是在构造函数中创建实例并在需要时重新使用它。当然,循环引用通常是一个糟糕的想法——它是增加代码复杂性的好方法,它使调试和测试更加昂贵。进一步的重构也会对循环引用造成更大的伤害。