0

This code has been UPDATED. 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; 
} 

Here,systinfo.X provides a null value. But mainfrm.stateInfo.X provides the correct value but throws marshal-by-reference class warning. What is the correct way of initializing systinfo? The values of state are obtained from a robot connected from the external.

srivas
  • 21
  • 9
  • 2
    Please provide a complete, valid example. `public void state systinfo` is clearly invalid, and there are other aspects of your example which are very hard to follow. It would also be clearer if you could follow .NET naming conventions. – Jon Skeet Jul 10 '15 at 10:30
  • 1
    Get rid of `ref` from `public Sub(ref Main main)`. In C++ parlance, you are passing a pointer to a pointer to `Main` with your code, which isn't what you want to do here. – David Arno Jul 10 '15 at 10:30
  • @DavidArno: `public Sub(ref Main main)` was autmoatically constructed when I implemented ` cpnew = new Sub(ref main); ` Moreover it throws an error when I try to modify the same. – srivas Jul 10 '15 at 11:13

1 Answers1

2

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.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • Thanks for the reply. But the problem persists. `systinfo.X` still produces a null value and `mainfrm.stateInfo` though produces the output, throws CS1690 exception (Marshal by reference). – srivas Jul 10 '15 at 15:50
  • @srivas Why shouldn't it be `null`? You never initialize it. – Luaan Jul 10 '15 at 15:59
  • I did initalized it as follows: `public Sub(Main main) { InitializeComponent(); this.main = main; systinfo = new state(); systinfo = mainfrm.stateInfo; }` – srivas Jul 10 '15 at 16:40
  • @srivas You may not realize this, but you've simply created a new instance (fine), assigned it to a field (fine), and then promptly replaced it with an unitialized one from `mainfrm`. – Luaan Jul 10 '15 at 17:15
  • please recommend the right way of initializing an object (`systinfo`) which covers the aspect of covering marshall by reference caused due to direct calling of (`mainfrm.stateinfo`). I am sorry I made a huge mistake. Here `mainfrm` and `main` are on and the same. – srivas Jul 10 '15 at 17:36
  • @srivas Can you try to update your question with a sample that actually works and displays the issue you're facing? It's a bit tricky trying to help when you don't have real code to work with :) – Luaan Jul 11 '15 at 18:06
  • @srivas That still doesn't compile. You need to provide a short, *working* sample code that reproduces your issue. Although now it's obvious that `X` can never be null, so it's even less clear what you mean by "Here,systinfo.X provides a null value.". – Luaan Jul 13 '15 at 10:22
  • I apologize Iam not in a poisiotn to provide the full code, since its too large and also contains confidential features. This is where stateInfo.X obtains its information from.: `stateInfo.X = this.P[0, 0]; stateInfo.Y = this.P[1, 0]; stateInfo.Z = this.P[2, 0]; ` P is a matrix that obtains its value from an external strucutre. – srivas Jul 13 '15 at 10:44
  • @srivas We don't need you to provide the full code - just figure out the simplest piece of code that shows the problem you're having and post that. Just keep removing stuff until there's nothing left to remove without also getting rid of the issue. – Luaan Jul 13 '15 at 10:53
  • the problematic part is the one I just posted. I am having problem with initalizing `systinfo`. As you had mentioned earlier, I am replacing it with the uniintialized one from `main`? How do I initialize it with the main, so it does not return null value. – srivas Jul 13 '15 at 11:05
  • @srivas I don't know - I have no idea what you're doing. That's the problem with the fact that your sample code doesn't compile. And if `systinfo` is a `struct` (as your new sample seems to imply), it simply *can't* be null, further confusing matters. Just prepare a piece of code that compiles and shows the problem you have, and I'll be able to help you. Without that, all I can do is guess. And I don't see you ever assigning to `systinfo` in `Main` - that's a bad sign. – Luaan Jul 13 '15 at 11:11
  • `systinfo` as of now is an object of a struct `state`. I am not sure whether this is the right way to initialize. should I declare systinfo in `Main.cs` ? If so, why? This does not compile because I do not know the correct form of initializing `systinfo`. Is there an alternate way to counter marshal-by reference other than creating/initalising `systinfo`? I do not want `main.stateInfo.X` to throw a marshal by reference. – srivas Jul 13 '15 at 11:35
  • @srivas The problem is, `struct`s are always passed by value by default. The way you're treating it indicates that's not how you're working with it - why is `state` a `struct`, when you aparently want to have multiple references to one instance of `state`? – Luaan Jul 13 '15 at 12:13
  • why is `state` a `struct`, when you aparently want to have multiple references to one instance of `state`? I do not quite understand this question. `state` is a `struct`. I do not wish to makes multiple reference to it. rather I want to copy the entire field of `main.stateInfo` into a single property? field so that it will not encounter marshal-by-reference value. – srivas Jul 13 '15 at 13:44
  • @srivas When you're constructing `Sub`, `main.stateInfo` isn't initialized yet. I assume that since `main.stateInfo` works eventually, it's assigned / initialized some time after `Sub` is constructed. By that time, `main.stateInfo` works fine, but `Sub` has no way of knowing that - it only has a copy of the data at the time it was constructed. Whenever you change `stateInfo` in `main`, you also have to change it in `Sub` - and vice versa. – Luaan Jul 13 '15 at 14:19
  • so in that case, would it help if I create systinfo in the `Main.cs` file itself like this: `public main() { InitializeComponent(); systinfo = this.stateInfo; cpnew = new Sub(systinfo); } ` ? previously I tried passing stateInfo, but it derived null values. – srivas Jul 13 '15 at 15:13
  • @srivas Yes - and in fact, it is very much preferred to only pass the minimum possible. In your original code, you've been passing the whole `Main` form, which gives you a lot more opportunities for error than passing just `systinfo`. Do keep in mind that each of those is a *separate* `stateInfo`, though - if you change any of the instances, the others will stay the same. This may be exactly what you intended, or it may not - depending on your requirements. Explicitly passing only what's necessary usually allows for code that's much easier to understand, and harder to break. – Luaan Jul 13 '15 at 15:32