It's a good thing you asked - remember to always follow the warnings unless you absolutely know what you're doing. In this case, you most definitely do not know what you're doing.
Form
is a class
- and all classes are reference types in .NET. This has several implications, one of which is highly relevant here - they are always passed by reference. In other words, when you use Main main
as an argument, you are already passing a reference (similar to passing a pointer to Main
in C).
Using ref
, you're passing a reference to the reference. This allows you to modify the outside reference from inside of the method. That's not what you want here - as a simple example, it would allow you to write an increment method:
public void Increment(ref int value)
{
value = value + 1;
}
If you didn't use ref
, this would simply modify the local value of value
. With ref
, it modifies the local in the caller.
In your case, the proper code would be closer to
public state stateInfo;
private readonly Sub cpnew;
public Main()
{
InitializeComponent();
cpnew = new Sub(this);
}
Form2:
public state systinfo;
private readonly Main main;
public Sub(Main main)
{
InitializeComponent();
this.main = main;
systinfo = mainfrm.stateInfo;
}
So, what is the warning telling you? Form
inherits from MarshalByRefObject
. This implies that you might not actually be passing the real Form
object - it's entirely possible you only have a proxy to a Form
on a remote computer, for example. This means that all the calls on the type are automatically marshalled through the proxy, executed on the actual instance, and the result returned. Since state
is a struct
(and I'm betting it's because you don't understand the difference between C#'s struct
and C's struct
), it's a value-type - and if you are indeed holding a proxy instead of the real instance, this will cause a runtime exception.
To get around the warning, you could copy out the state
to a local first - that makes it safe (and more importantly, obvious).
There's a lot of traps you can drop into when switching from C++ to C# - they look similar on the surface, but there's many differences. Try looking up a bit about whatever you're trying to use before you actually do - for example, looking up the ref
keyword would make it obvious that you're making a pointer to a pointer, and looking up struct
and class
will tell you that they behave completely differently from C++. Just be careful.
Coding in C# idiomatically gets even more serious. For example, you usually create sub-forms and dialogs where you need them, rather than creating an instance in the constructor and reusing it when needed. And of course, circular references are usually a terrible idea - it's a great way to increase the code complexity, and it makes debugging and testing more expensive. Further refactoring hurts a lot more with circular references as well.