I want to send a reference to a struct to a form. Then I need to store the reference so I can do changes to a member of that struct before the form is closed. Here's the code:
struct mystruct
{
public int myvar;
}
public partial class myForm : Form
{
private mystruct refonstruct;
public myForm(ref mystruct ms)
{
// refonstruct will be a copy, not a reference :-(
refonstruct = ms;
// how can I get a reference instead?
}
public myForm_FormClosing()
{
// since refonstruct is not a reference the next line will not change foostruct
refonstruct.myvar = 17;
}
}
public void foo()
{
mystruct foostruct;
foostruct.myvar = 0;
using(myForm f= new myForm(ref foostruct))f.ShowDialog();
// here foostruct, myvar will still be 0 since refonstruct is a copy not a reference
}
Passing a struct as refernce in the constructor is not the problem. If I would be able to do changes to the member of the struct there (ms.myvar = 17) it would work. But I can only apply the changes before closing the dialog. In case I could use a class instead all would be no problem, I know, but I for so many reasons (e.g. existing huge project, file format, etc.) I cannot. Summary: Is there a way to store a reference to a struct in a member variable? Thanks.
If you want forms to share data a struct is not the correct approach to use. Structs are value types, and stored in the context where they are used. This would be the stack frame of foo() in this case. Since myForm is a class, it can have a longer lifetime than foo(). So if it could store a reference, that reference might be invalid and refer to some random position on the callstack, and that is just not allowed.
The easiest option is to just change mystruct to a class.
An alternative is to introduce a wrapper around the struct:
public class Ref<T>
{
public T Value { get; set; }
public Ref(T value) => Value = value;
}
That way your struct can be immutable, and you would just replace the entire struct when it needs to change. You can also add an event that is raised when the value is set, to let any form know if it needs to update itself to show the updated value.
Related
I have a question about creating an immutable struct inside a class definition. I want to define the struct outside the class but use that same struct type in the class definition while maintaining immutability. Will the code below achieve this?
namespace space
{
class Class1
{
public Struct {get; set;}
}
public Struct
{
public Struct(string strVar)
{
StructVar = strVar;
}
public string StructVar {get;}
}
}
Also, if I have a struct within a struct like:
class Class1
{
public Struct2 {get; set;}
}
public struct Struct2
{
public Struct2(string str, InStruct inStrct)
{
StrVar = str;
InStruct = inStrct;
}
public string StrVar {get;}
public InStruct InStruct {get;}
}
public struct InStruct
{
public InStruct(Array ary)
{
StrArray = ary
}
public Array StrArray {get;}
}
Does this also maintain immutability?
Lastly, if the size of the array in the InStruct is likely to be quite long, should I not use a struct at all and just put the array itself into the class definition instead? Am I just going struct crazy?
My concern is that because I'm doing a {set;} in the class definition that I'm breaking a rule somewhere. I would put the struct in the class definition itself but I didn't like to have to continuously call class constructors over and over to create each struct, that kind of seemed to defeat the purpose of using a struct in the first place.
It's a little difficult to give a complete answer without understanding exactly what you are trying to accomplish, but I'll start with a few important distinctions.
First, in C#, the struct/class distinction isn't about mutability per se. You can have a immutable class, like this one
public class CannotBeMutated
{
private string someVal;
public CannotBeMutated(string someVal)
{
_someVal = someVal
}
public string SomeVal => _someVal;
}
and a mutable struct, like this one
// This is not at all idiomatic C#, please don't use this as an example
public struct MutableStruct
{
private string _someVal;
public MutableStruct(string someVal)
{
_someVal = someVal;
}
public void GetVal()
{
return _someVal
}
public void Mutate(string newVal)
{
_someVal = newVal;
}
}
Using the above struct I can do this
var foo = new MutableStruct("Hello");
foo.mutate("GoodBye");
var bar = foo.GetVal(); // bar == "GoodBye"!
The difference between structs and classes is in variable passing semantics. When an object of a value type (e.g. a struct) is assigned to a variable, passed as a parameter to or returned from a method (including a property getter or setter) a copy of the object is made before it is passed to the new function context. When a object of a reference type is passed as a parameter to or returned from a method, no copy is made, because we only pass a reference to the object's location in memory, rather than a copy of the object.
An additional point on struct 'copying'. Imagine you have a struct with a field that is a reference type, like this
public struct StructWithAReferenceType
{
public List<string> IAmAReferenceType {get; set;}
}
When you pass an instance of this struct into a method, a copy of the reference to the List will be copied, but the underlying data will not. So if you do
public void MessWithYourSruct(StructWithAReferenceType t)
{
t.IAmAReferenceType.Add("HAHA");
}
var s = new StructWithAReferenceType { IAmAReferenceType = new List()};
MessWithYourSruct(s);
s.IAmAReferenceType.Count; // 1!
// or even more unsettling
var s = new StructWithAReferenceType { IAmAReferenceType = new List()};
var t = s; // makes a COPY of s
s.IAmAReferenceType.Add("hi");
t.IAmAReferenceType.Count; // 1!
Even when a struct is copied, its reference type fields still refer to the same objects in memory.
The immutable/mutable and struct/class differences are somewhat similar, insofar as they are both about where and whether you can change the contents of an object in your program, but they are still very distinct.
Now on to your question. In your second example, Class1 is not immutable, as you can mutate the value of Struct2 like this
var foo = new Class1();
foo.Struct2 = new Struct2("a", 1);
foo.Struct2 // returns a copy of Struct2("a", 1);
foo.Struct2 = new Struct2("b", 2);
foo.Struct2 // returns a copy of Struct2("b", 2);
Struct2 is immutable, as there is no way for calling code to change the values of StrVar or InVar once. InStruct is similarly immutable. However, Array is not immutable. So InStruct is an immutable container for a mutable value. Similar to if you had a ImmutableList<List<string>>. While you can guarantee calling code does not change the value of InStruct.StrArray to a different array, you can do nothing about calling code changing the value of the objects in the Array.
Finally, some generic advice related to your example.
First, mutable structs, or structs with mutable fields, are bad. The examples above should point to why structs with mutable fields are bad. And Eric Lippert himself has a great example of how terrible mutable structs can be on his blog here
Second, for most developers working in C# there's almost never a reason to create a user defined value type (i.e. a struct). Objects of value types are stored on the stack, which makes memory access to them very fast. Objects of reference types are stored on the heap, and so are slower to access. But in the huge majority of C# programs, that distinction is going to be dwarfed by the time cost of disk I/O, network I/O, reflection in serialization code, or even initialization and manipulation of collections. For ordinary developers who aren't writing performance-critical standard libraries, there's almost no reason to think about the performance implications of the difference. Heck, developers in Java, Python, Ruby, Javascript and many other languages get by in languages totally without user-defined value types. Generally, the added cognitive overhead they introduce for developers is almost never worth any benefit you might see. Also, remember that large structs must be copied whenever they are passed or assigned to a variable, and can actually be a performance problem.
TL;DR you probably shouldn't use structs in your code, and they don't really have anything to do with immutability.
In implementing a Service Locator, I've come across something I'm confused about with regards to reference types.
In the code below, I have a static class ServiceLocator which exposes 2 static methods, GetService and ProvideService - get returns the current service, and provide takes a new service as an argument and assigns it to the current service variable. If the provided service is null, it assigns currentService to a static defaultService initialised at the start of the class declaration. Simple stuff:
public static class ServiceLocator {
private static readonly Service defaultService = new Service();
private static Service currentService = defaultService;
public static Service GetService() {
return currentService;
}
public static void ProvideService(Service service) {
currentService = service ?? defaultService;
}
}
What i'm confused about is this: I have a separate class which stores a reference to the currentService at the start of its class declaration in the variable named referenceToCurrentServiceAtStart. When I provide the service locator with a new Service instance to update the current service, referenceToCurrentServiceAtStart appears instead to maintain the reference to defaultService:
public class ClassThatUsesService {
private Service referenceToCurrentServiceAtStart = ServiceLocator.GetService();
private static ClassThatUsesService() {
ServiceLocator.ProvideService(new Service());
// this variable appears to still reference the defaultService
referenceToCurrentServiceAtStart != ServiceLocator.GetService()
}
}
So the references appear to follow this kind of chain:
referenceToCurrentServiceAtStart -> defaultService -> (Service in memory)
Which is understandable, since referenceToCurrentServiceAtStart simply copies the currentService reference. However, the behaviour I'm looking for/would like is for referenceToCurrentServiceAtStart to always reference whatever currentService references, so it's updated by Provide(). Something more akin to:
referenceToCurrentServiceAtStart -> currentService -> (Service> in memory)
So, is this behaviour possible? I'm really unsure of how I'd achieve this kind of reference behaviour. I'm new to C# so it's very possible there's some obvious language feature I'm clueless about. Any help would be greatly appreciated.
is this behaviour possible?
No, not as you've described it. As you're already aware, all you get is a copy of the original reference. Changing the original reference doesn't change the copy, any more than copying the value of an int variable to another would allow you to later change the original and have the copy change:
int original = 17;
int copy = original;
original = 19;
// "copy" is still 17, of course!
If you want to always have the current value of the reference in ServiceLocator, then you should just always retrieve the value from that class, rather than using a local field. In your above example, you might indirect through a property, e.g.:
public class ClassThatUsesService {
private Service referenceToCurrentServiceAtStart => ServiceLocator.GetService();
}
It's a one character change (the = becomes =>), but don't be fooled. It's a significant change in implementation. What you wind up with instead of a field, is a read-only property (i.e. has only a get method and no set method), where that property's get method calls the ServiceLocator.GetService() method and returns the result.
Personally, I wouldn't bother. Unless you have some very strong expectation that the implementation of referenceToCurrentServiceAtStart will change in the future, you should just call ServiceLocator.GetService() directly. Don't even have the referenceToCurrentServiceAtStart property. Since the code expects to always get the current value, the best way to ensure that is to just always get the current value, straight from the class where that value is stored.
Finally, I'll take the opportunity to show a scenario that is similar to what you're asking, but not exactly. In particular, because you're trying to store the reference in a class field, the above is how you need to do it. But, the latest C# has "reference return values", which must be stored in "ref locals". Since you want to reference a static field, which is guaranteed to always exist, you can in fact return a reference to the field, store that in a local, and when you retrieve the local variable's value, it will always have whatever is in the field, because it's a reference to the field, not a copy of it.
You can see the example in the documentation (see links above), but here's another example that is more similar to what you're doing:
class Program
{
static void Main(string[] args)
{
// stores a reference to the value returned by M1(), which is to say,
// a reference to the B._o field.
ref A a1 = ref B.M1();
// Keep the original value, and create a new A instance
A original = a1, a2 = new A();
// Update the B._o field to the new A instance
B.M2(a2);
// Check the current state
Console.WriteLine($"original.ID: {original.ID}");
Console.WriteLine($"a1.ID: {a1.ID}");
Console.WriteLine($"a2.ID: {a2.ID}");
}
}
class A
{
private static int _id;
public int ID { get; }
public A()
{
ID = ++_id;
}
}
class B
{
private static A _o = new A();
public static ref A M1()
{
// returns a _reference_ to the _o field, rather than a copy of its value
return ref _o;
}
public static void M2(A o)
{
_o = o;
}
}
When you run the above, you'll get this output:
original.ID: 1
a1.ID: 2
a2.ID: 2
In other words, the variable a1 winds up yielding the same value found in a2, which is the new object passed to the B.M2() method to modify the B._o field, while the original copy of the B._o field value remains a reference to the original object that field referenced.
This doesn't work in your case, because the ref value that's returned has to be stored in a ref local. You can't put it into a class field. But it's similar enough to your scenario that I wanted to mention it, in case you want to change your design to allow that, or want to use that technique in some other scenario that does work in that way.
I have three classes (Data, First, Second ).
I'm creating member of Data in First and try to pass it to Second with the following:
public class First
{
public Data DataMember;
Second SecondMember;
void First_Function()
{
SecondMember.Second_Function(ref DataMember);
}
}
public class Second
{
Data DataMember;
public void Second_Function(ref Data data)
{
}
}
Is there a way to access the First.Data member in Second.Data member?
Using ref in the Second.Second_Function() allows me to access the member of the First but only inside the Second_Function().
I want another function in Second to access it, that has a different "call back time" as the Second_Function().
Edit :
My question in not about what is the difference between the reference and value type .
if I use ref keyword for a int variable , that mean if I replace it with another value it will effect the original .
in class when I have two variable reference to the same instance if I edit one of them I effect the other , that's because they reference to the same thing ,I want to know if there is a way in C# to replace one of the variable ,and make the other variable change with it .
There are two kinds of types in C#: reference types and value types.
Variables of reference types store references to their data (objects),
while variables of value types directly contain their data. With
reference types, two variables can reference the same object;
therefore, operations on one variable can affect the object referenced
by the other variable. With value types, each variable has its own
copy of the data, and it is not possible for operations on one
variable to affect the other (except in the case of ref and out
parameter variables, for more details see here
Here an example:
Explanation
Pass your data object to the class First, Second as parameter in the constructor
Any updates happens on the data object inside First or Second will be reflected on the data object outside these classes because it is reference type
public class Data{
public Data(int value)
{
this.Value = value;
}
public int Value{get;set;}
}
public class First{
private Data m_data;
public First(Data data)
{
m_data = data;
}
public void Add(int value)
{
if(m_data!=null)
m_data.Value+=value;
}
}
public class Second{
private Data m_data;
public Second(Data data)
{
m_data = data;
}
public void Multiply(int value)
{
if(m_data!=null)
m_data.Value*=value;
}
}
now let us setup this scenario
var data = new Data(10);
var first = new First(data);
var second = new Second(data);
second.Multiply(5);
first.Add(10);
What do you expect the value inside the class data? 10? you are wrong, the value is 60
Here a working demo
Hope this will help you
*Solved. Thanks for the explanations guys, I didn't fully understand the implications of using a value type in this situation.
I have a struct that I'm using from a static class. However, the behavior is showing unexpected behavior when I print it's internal state at runtime. Here's my struct:
public struct VersionedObject
{
public VersionedObject(object o)
{
m_SelectedVer = 0;
ObjectVersions = new List<object>();
ObjectVersions.Add(o);
}
private int m_SelectedVer;
public int SelectedVersion
{
get
{
return m_SelectedVer;
}
}
public List<object> ObjectVersions;//Clarifying: This is only used to retrieve values, nothing is .Added from outside this struct in my code.
public void AddObject(object m)
{
ObjectVersions.Add(m);
m_SelectedVer = ObjectVersions.Count - 1;
}
}
Test code
VersionedObject vo = new VersionedObject(1);
vo.AddObject(2);//This is the second call to AddObject()
//Expected value of vo.SelectedVerion: 1
//Actual value of vo.SelectedVersion: 1
Now, if you test this code in isolation, i.e., copy it into your project to give it a whirl, it will return the expected result.
The problem; What I'm observing in my production code is this debug output:
objectName, ObjectVersions.Count:2, SelectedVer:0,
Why? From my understanding, and testing, this should be completely impossible under any circumstances.
My random guess is that there is some sort of immutability going on, that for some reason a new struct is being instanced via default constructor, and the ObjectVersions data is being copied over, but the m_SelectedVersion is private and cannot be copied into the new struct?
Does my use of Static classes and methods to manipulate the struct have anything to do with it?
I'm so stumped I'm just inventing wild guesses at this point.
Struct is value type. So most likely you are creating multiple copies of your object in your actual code.
Consider simply changing struct to class as content of your struct is not really good fit for value type (as it is mutable and also contains mutable reference type).
More on "struct is value type":
First check FAQ which have many good answers already.
Value types are passed by value - so if you call function to update such object it will not update original. You can treat them similar to passing integer value to function: i.e. would you expect SomeFunction(42) to be able to change value of 42?
struct MyStruct { public int V;}
void UpdateStruct(MyStruct x)
{
x.V = 42; // updates copy of passed in object, changes will not be visible outside.
}
....
var local = new MyStruct{V = 13}
UpdateStruct(local); // Hope to get local.V == 42
if (local.V == 13) {
// Expected. copy inside UpdateStruct updated,
// but this "local" is untouched.
}
Why is this a struct and not a class? Even better, why are you tracking the size of the backing store (List<T>) rather than letting the List<T> track that for you. Since that underlying backing store is public, it can be manipulated without your struct's knowledge. I suspect something in your production code is adding to the backing store without going through your struct.
If it were me, I'd set it up something like this, though I'd make it a class...but that's almost certainly a breaking change:
public struct VersionedObject
{
public VersionedObject()
{
this.ObjectVersions = new List<object>() ;
return ;
}
public VersionedObject(object o) : this()
{
ObjectVersions.Add(o);
return ;
}
public VersionedObject( params object[] o ) : this()
{
ObjectVersions.AddRange( o ) ;
return ;
}
public int SelectedVersion
{
get
{
int value = this.ObjectVersions.Count - 1 ;
return value ;
}
}
public List<object> ObjectVersions ;
public void AddObject(object m)
{
ObjectVersions.Add(m);
return ;
}
}
You'll note that this has the same semantics as your struct, but the SelectedVersion property now reflects what's actually in the backing store.
How would I get the parent class of an object that has a value of null?
For example...
ClassA contains int? i which is not set to any value when the class is created.
Then in some other place in the code I want to pass in i as a parameter to some function. Using i as the only info, I want to be able to figure out that ClassA "owns" i.
The reason for this is because ClassA also contains some other object, and I want to call this other object's value from that same function mentioned in the above paragraph.
Could also be:
public class A
{
public class B
{
public int? i;
public int? j;
}
B classBInstance = new B();
public string s;
}
{
...
A someClassAInstance = new A();
...
doSomething(someClassAInstance.classBInstance.i);
...
}
public static bool doSomething(object theObject)
{
string s = /* SOMETHING on theObject to get to "s" from Class A */;
int someValue = (int)theObject;
}
You can't. Pass an instance of A to doSomething.
class A is not the Parent (base) of its members. Just their holder.
So you cannot do what you want, passing an int or int? around doe not involve any information about the class.
The parameter that is sent to the method doesn't contain any information that you can use to determine which object it originally came from. What's sent to the method is just a copy of the nullable int, boxed in an object.
So what you are asking for is not possible. The only way to do something like that would be to analyse the call stack to find the calling method, then analyse the code in that method to determine where the parameter value was taken from.
Cant you use a dictionary or keyvaluepairs instead so that the int is linked to "s" that way? The problem is that an int is not aware of which object owns it.
Its not possible since you are passing 'i' which is a member of class B. But class B does not hold a reference to an instance of class A. An instance is required to get the value of 's' since its a non-static field.