Event not fired when copying entire object. How to do it? - c#

If I have a class that contains some properties and methods, and when a property is changed, it fires an event (in this case passing a string in the args):
public class Settings
{
public delegate void SettingsChangedHandler(object sender, string e);
public event SettingsChangedHandler SettingsChanged;
private string rootfolder;
public string RootFolder
{
get { return rootfolder; }
set
{
rootfolder = value;
if (SettingsChanged != null)
SettingsChanged(this, "ROOT_FOLDER");
}
}
}
If i have somewhere in my code:
public Settings SettingsInstance = new Settings();
SettingsInstance.SettingsChanged += new SettingsChangedHandler(SettingsInstance_SettingsChanged);
SettingsInstance = SomeOtherSettingsInstance;
I want all of the properties that have changed to fire their events.
How do I achieve something like this? Surely I don't have to copy them over one at a time?

This line of code:
SettingsInstance = SomeOtherSettingsInstance;
does not copy anything inside the objects, instead it overwrites the reference stored in SettingsInstance with the reference stored in SomeOtherSettingsInstance.
The object itself is none the wiser.
Basically, after you have executed the first of the 3 last lines, you have this scenario:
SomeOtherSettingsInstance -----> Object 1 in memory of type Settings
SettingsInstance --------------> Object 2 in memory of type Settings
^
|
+- References
After you've executed the third line, this is how it looks:
SomeOtherSettingsInstance --+--> Object 1 in memory of type Settings
/
SettingsInstance ---------+ Object 2 in memory of type Settings
Now you have two references to the first object, one through each variable, and you've left the new object you just created to rot for the garbage collector to come pick it up later.
If you wish to copy the internals, then yes, you have to copy one property at a time.
I regularly create cloning support like this:
public Settings Clone()
{
Settings clone = CreateCloneInstance();
CloneTo(clone);
return clone;
}
protected virtual Settings CreateCloneInstance()
{
return new Settings();
}
public virtual void CloneTo(Settings clone)
{
clone.RootFolder = RootFolder;
... + any other properties you might have
}
In your scenario, you want to hook up an event before copying things, so you would call it like this:
public Settings SettingsInstance = new Settings();
SettingsInstance.SettingsChanged += SettingsInstance_SettingsChanged;
SomeOtherSettingsInstance.CloneTo(SettingsInstance);
The reason I implement cloning support like that is due to object hierarchies. If that is not an issue for you (you're not going to inherit from Settings), you can just do this:
public Settings Clone()
{
Settings clone = new Settings();
CloneTo(clone);
return clone;
}
public void CloneTo(Settings clone)
{
clone.RootFolder = RootFolder;
... + any other properties you might have
}

Why not just perform the initialization the other way around?
Settings SettingsInstance = SomeOtherSettingsInstance;
SettingsInstance.SettingsChanged += new SettingsChangedHandler(SettingsInstance_SettingsChanged);
The way you are currently performing the assignment you will overwrite your instance, SettingsInstance, where you just configure the SettingsChanged event.
I believe you would still need to copy everything manually to make sure all of the fields on the new instance are correct. You might be able to get by with a shallow copy using Object.MemberwiseClone. For a more in-depth discussion of a Shallow Copy vs. Deep Copy see this wikipedia link.

This is because properties are not changing, you are just reassigning references.

As Lasse pointed out, assignment to a reference variable just changes what object that variable refers to, and does nothing to the object.
The meaning of assignment is rigidly controlled by the C# compiler. You can override it on a property, but not on a local variable. So the closest you can get to a pattern for this is:
interface IWantAssignmentNotification
{
void LostAssignment();
void GainedAssignment();
}
class Ref<T> where T : IWantAssignmentNotification
{
private T _value;
public T Value
{
get { return _value; }
set
{
if (_value != null)
_value.LostAssignment();
_value = value;
if (_value != null)
_value.GainedAssignment();
}
}
}
Now your Settings class has to implement IWantAssignmentNotification, and you can use Ref<Settings> to hold a reference to it:
Ref<Settings> refSettings = new Ref<Settings> { Value = new Settings() };
refSettings.Value = someOtherSettingsInstance;
The first line will call GainedAssignment on the new instance of Settings. The second line will call LostAssignment on that instance followed by GainedAssignment on the other instance. The idea being that you would make Settings fire certain events in either or both of those.
But of course, this doesn't stop the erroneous:
refSettings = new Ref<Settings> { Value = someOtherSettingsInstance };
That simply discards the old Ref<T> object, and so no one ever tells the previous Settings instance that it is no longer assigned to a "live" variable.

Related

Visibility inside a class of objects created locally

Here it is a sample code in Windows Forms:
namespace WindowsFormsApplication1
{
public class contained
{
public int value;
}
public class container
{
public List<contained> c1 = new List<contained>();
public void add_contained()
{
contained tmp = new contained();
tmp.value = 1; // some default value
c1.Add(tmp);
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
container cnt = new container();
cnt.add_contained();
int i = cnt.c1[0].value; // this works, why?
}
}
}
Practically, I have a big class "container" that manages a list of complex objects "contained". There is a procedure adding a new blank object to the list - to be modified later. Now, I ran the code above and it works, but I do not understand well why.
If the procedure "add_contained" to add a default object to the list creates one locally, I expect it disappear when the procedure exits, so the list should remain with a null pointer. Instead, I can still access the object in the list, as indicated in the last line "int i=...".
Actually, I read the garbage collector is non deterministic, it is unclear what it means, it seems it does not do things in precise moments. But, that means the above code works because it is short? If I accessed the list a bit later (ie in a more complex program) it could not work?
What is the correct way to solve the problem outlined by the code above? Thanks.
When you do new contained() a new object is created and stored "somewhere".
Then a reference to it is assigned to tmp.
That same reference is in turn added to the list and you exit the method.
At that point the variable tmp is "destroyed" but the object is still in memory (because it's still referenced through the List).
If at some point you remove the list item, the reference on that object ; and there are no other reference on that object ; it becomes eligible for collection, meaning the GC can free it's memory.

Replace object instance with another in C#

In this question I would like to find out if and how this is possible. This technique would seem extremely bad practice but it seems that the API (UnityEditor) that I am using, is doing something like this and I am just curious.
If there are multiple references to the same object, is it possible to instantiate a new object into the same memory slot so that all previous references point to the new object?
I figured out that the only feasible way to do so is by using unmanaged C++. Essentially the following is happening:
// Original prefab
GameObject prefab = x;
prefab.tag = "Untagged";
// A copy of the original prefab
GameObject prefabCopy = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
prefabCopy.tag = "EditorOnly"; // Change from initial value "Untagged"
Debug.Log(prefab.tag); // "Untagged" - expected
Debug.Log(prefabCopy.tag); // "EditorOnly" - expected
// Replace contents of prefab file with `prefabCopy`
PrefabUtility.ReplacePrefab(prefabCopy, prefab);
// Destroy the copy
DestroyImmediate(prefabCopy);
Debug.Log(prefab.tag); // "EditorOnly" - whoa?
Some how prefab is now pointing to a different object?
Note: Bear in mind that Unity is built on top of the Mono flavour of .NET
Since an object state is defined by field values, you can copy memory, containing field values, from one object to another, effectively "replacing" it:
public static void Replace<T>(T x, T y)
where T : class
{
// replaces 'x' with 'y'
if(x == null) throw new ArgumentNullException("x");
if(y == null) throw new ArgumentNullException("y");
var size = Marshal.SizeOf(typeof(T));
var ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(y, ptr, false);
Marshal.PtrToStructure(ptr, x);
Marshal.FreeHGlobal(ptr);
}
Note that this code requires [StructLayout(LayoutKind.Sequential)] (or LayoutKind.Explicit) attribute defined for a class.
You could do that if you embed your object into another one that is used to access the object.
class ObjectReference<T>
where T : new()
{
private T _obj = new T();
public void CreateNewObject()
{
_obj = new T();
}
public T Value { get return _obj; }
}
Now you can create multiple references to an object of type ObjectReference and only change the local object. The "real" object would be accessed through the Value property
A slightly different approach is that you create a wrapper that implements the same interface as your "real" object, thus making this wrapping transparent.
interface ISomeInterface
{
string PropertyA { get; set }
void MethodB (int x);
}
class TheRealObject : ISomeInterface
{
public string PropertyA { get; set }
public void MethodB (int x)
{
Console.WriteLine(x);
}
}
class Wrapper : ISomeInterface
{
TheRealObject _obj = new TheRealObject();
public string PropertyA
{
get { return _obj.PropertyA; }
set { _obj.PropertyA = value; }
}
public void MethodB (int x)
{
_obj.MethodB(x);
}
public void CreateNewObject()
{
_obj = new TheRealObject();
}
}
Now the wrapper can be used as if it was the "real" object. You could also pass an initial instance of the "real" object in the wrapper's constructor and remove the initializer of _obj.
No, that's not possible.
To actually change all references to an object, you would have to freeze all threads in the process, and access their register sets and stack. That's what the garbage collector does, but it's not possible for regular code.
What the method most likely does is to make a deep copy of one object onto the other.
If it is a custom Class you want to reference, i think you can have all the references point to a Fake Reference...
create your class (A)
create your class Interface (IA)
Create a wrapper class based on your interface which just passes all calls to a contained object (AC)
I Added a Assignment operator so i have all A Objects as ACs.
class AC:IA
{
IA ref;
AC(IA ref)
{
this.ref = ref;
}
public void ChangeReference(IA newRef) { ref = newRef;}
public static operator = (IA assignedObj)
{
return (assignedObject is AC) ? assignedObject : new AC(assignedObj);
}
// implementation of all methods in A
public override string ToString() { return ref.ToString(); }
...
}
Now if you want, you can use the ChangeReference method to switch all to the new Reference..
in C++ you would use Reference to Reference
Best of luck

Privately scoped variable only for use within property

Is it possible to have a variable which is an instance variable within a class but can only be accessed by a specific property?
I quite often create "self-creating" properties like so ...
private IWGSLocation _location;
public IWGSLocation Location
{
get
{
_location = _location ?? new WGSLocation();
_location.Latitude = Latitude.GetValueOrDefault(0);
_location.Longitude = Longitude.GetValueOrDefault(0);
return _location;
}
}
which means that I don't go re-creating a new WGSLocation (or whatever other kind of object I need, which may be expensive to create, or may only need to be created once) every time I access the property. The downside is that my class can access the _location variable. But I don't really want it to, so if there any way of having an instance variable which can only be used within the property itself?
I'm thinking something along these lines ...
public IWGSLocation Location
{
get
{
WGSLocation _location = _location ?? new WGSLocation();
_location.Latitude = Latitude.GetValueOrDefault(0);
_location.Longitude = Longitude.GetValueOrDefault(0);
return _location;
}
}
I agree it would be a nice language feature to have persistent locals -- that is, variables whose lifetimes are based on the lifetime of the instance but whose scopes (the region of program text in which it is legal to access the variable by name) are local. It would be nice to have "static" locals as well, as some languages do.
Sadly, this is not a feature of C# and we have no plans to add it. It's nice to have, but nice to have is not good enough to justify the expense, or to postpone or cancel a "nicer to have" feature.
It's only "nice to have" because of course if you have a private field, it already is a private implementation detail of the class. If you don't want it used outside the property, then don't write code that uses it outside the property. If one of your coworkers tries to do so, put the smack down on 'em in code review.
I thought I might add: be very careful when writing property getters that mutate state. By default property getters are evaluated while looking at an object in the debugger, and it can be very confusing to be debugging something and have the debugger changing the values of fields just because you are examining an object.
The fact that the class can access it isn't necessarily a downside. It is still logically encapsulated in the same entity.
What you are after isn't possible in the way you want it to be. Member variables are visible by all areas of the class and local variables are restricted to their defined scope.
What you could instead do is have the location wrapped inside a container class. This class is your member variable. When returning the IWGSLocation you simply drill into the container class:
public class LocationContainer
{
public IWGSLocation InnerLocation { get; private set; }
public void SetLocation(WGSLocation loc)
{
InnerLocation = loc;
}
}
private readonly LocationContainer _container = new LocationContainer();
public IWGSLocation Location
{
get
{
if (_container.InnerLocation == null)
{
_container.SetLocation(...);
}
return _container.InnerLocation;
}
}
This won't stop the class from touching _container, but it will make other developers think twice before they do and they won't be able to accidentally mutate the location without explicitly calling SetLocation.
You could even then put set-once guarding in the SetLocation of the container.
Update: I'd actually use the lazy class here, something like:
private readonly Lazy<IWGSLocation> _location = new Lazy<IWGSLocation>(()
=>
{
var l = new WGSLocation();
l.Latitude = Latitude.GetValueOrDefault(0);
l.Longitude = Longitude.GetValueOrDefault(0);
return l;
});
public IWGSLocation Location
{
get { return _location.Value; }
}
Be warned, this was head-compiled! :-)
Your current implementation looks broken to me.
var x=obj.Location;
x.Latitude = 1;
Console.WriteLine(x.Latitude);//1
var y=obj.Location;
Console.WriteLine(x.Latitude);//WTF it changed
I recommend making IWGSLocation immutable, or only modifying it on creation, depending on which semantics you want.

C# 3.0 Object Initialation - Is there notification that the object is being initialized?

We have several domain objects which need to support both read-only and read-write modes; they currently have a bool Locked property for this--when Locked attempts to alter properties on the object result in an InvalidOperationException. The default state for the objects is Locked.
The object-initialization syntax of C# 3 introduces a small issue with these, in that the object must be unlocked (or default to be unlocked) during initialization and then locked explicityly at the end.
When using C# 3's object initialization syntax is there a means of receiving notification that the object is being intitialized or that initialization is complete? System.ComponentModel.ISupportInitialize was my best hope, but it doesn't get called.
You could use a fluent API and append it:
var obj = new MyType { Id = 123, Name = "abc"}.Freeze();
where the Freeze method returns the same instance (fluent) - something like:
class MyType {
private bool isFrozen;
public MyType Freeze() {
isFrozen = true;
return this;
}
protected void ThrowIfFrozen() {
if (isFrozen) throw new InvalidOperationException("Too cold");
}
private int id;
public int Id {
get { return id; }
set { ThrowIfFrozen(); id = value; }
}
private string name;
public string Name {
get { return name; }
set { ThrowIfFrozen(); name = value; }
}
}
(you could centralize the check a bit more if needed)
No, there is no such notification mechanism. The object initializer feature will simply call the specified constructor and then set the accessible fields / properties in the order they are listed. There is no interface available which supports notifications for this feature.
No. The object initializers just are a compiler feature to assist in initializing your objects. They call the properties directly.
You need to either force constructor usage, or add a "lock" method to lock them down explicitly.

Should I use a Field or Property within the class to set values

So I got into a friendly argument with a co-worker over a piece of code:
public sealed class NewObject
{
private string _stuff = string.Empty;
public string Stuff
{
get { return GetAllStuff(); }
}
private string GetAllStuff()
{
//Heavy string manipulation of _stuff
}
public NewObject(string stuffToStartWith)
{
_stuff = stuffToStartWith;
}
public static NewObject operator +(NewObject obj1, NewObject obj2)
{
if (obj1 == null)
throw new ArgumentNullException();
if (obj2 == null)
throw new ArgumentNullException();
NewObject result = new NewObject(string.Empty);
result._stuff = String.Concat(obj1._stuff, obj2._stuff);
return result;
}
}
The argument was over the operator override. My co-worker feels that it's not best programming practice to set values of private fields anywhere but the constructor. The solution proposed by my co-worker was to refactor the name of the Stuff property to AllStuff and add a property, Stuff, that has a get AND set accessor and use the new Stuff property in the operator override. Making it look like this:
public static NewObject operator +(NewObject obj1, NewObject obj2)
{
if (obj1 == null)
throw new ArgumentNullException();
if (obj2 == null)
throw new ArgumentNullException();
NewObject result = new NewObject(string.Empty);
result.Stuff = String.Concat(obj1.Stuff, obj2.Stuff);
return result;
}
I disagree. I feel the first way is better since it keeps the property read-only outside the class. My question is, which way is the best practice for object-oriented design?
You could give yourself a private set on the property (which would retain visibility or lack thereof while allowing you to use property syntax), but that doesn't really address the point.
Within the class, I say that variables are fair game. Anywhere outside, including inherited classes, should get and set the property, but within the declaring class I say it's OK to assign the private member.
The general issue has to do with a contract policy.
The notion of a (public set) property is that when it is called, other actions may be taken in addition to the semantic notion of changing state. For example, calling a setter may fire events, trigger a peripheral device and so on.
Your coworker is saying that by not using the property, you're side-stepping the contract and no events will be fired.
So here's you should do from your coworker's point of view:
this.Prop = CalculateSomeValue();
if (this.Prop < kPropMin) {
this.Prop = kPropMin;
}
else if (this.Prop > kPropMax * 2) {
this.Prop = kPropMax * 2;
}
this.Prop = this.Prop / 2;
Now, this is a contrived case, but I've just hit a possible heavyweight property up to three times in the get and up to three times in the set, and one of those might be illegal (setting to kHighLimit / 2). I can work around this by using a local and calling the set precisely once at the end. I'd rather just mess with the field, though.
I think a better approach is to take it pragmatically: use the property inside your class if and only if you want to invoke all the side-effects of a set or a get, otherwise obey the spirit of the property instead.
-- clarification --
By obey the spirit of the property, let's say that my set property looks like this:
bool PropValueOutOfRange(int val) {
return val < kPropMin || val > kPropMax;
}
public int Prop {
set {
if (PropValueOutOfRange(value))
throw new ArgumentOutOfRangeException("value");
if (PropValueConflictsWithInternalState(value))
throw new ArgumentException("value");
_prop = value;
NotifyPeriperalOfPropChange(_prop);
FirePropChangedEvent(/* whatever args might be needed */);
}
}
In this I've factored out a lot of the grungy details, but that lets me reuse them. So now I feel confident in touching the private field _prop because I have the same infrastructure for making sure that I keep it in range and to notify the peripheral and fire the event.
This lets me write this code:
_prop = CalculateSomeValue();
if (_prop < kPropMin)
_prop = kPropMin;
else if (_prop > kPropMax * 2)
_prop = kPropMax;
_prop /= 2;
NotifyPeripheralOfPropChange();
FirePropChangedEvent();
I'm using the same tools as those used to build the property so I'm working within the spirit of the property. I maintain correct range (but don't throw - I know better, I'm the implementer), hit the peripheral and fire events, and I do it thoughtfully, readably, and efficiently - not indiscriminately.
You're right
err... to elaborate, your private variables are yours to do as you please. If someone does an operation on you that changes the value of the object, (especially something like +), theres nothing wrong with modifying the value outside of the constructor. Thats the whole point of them being private.
Unless you want it immutable...
Update
The more i think about it, the more I believe your co-worker is confusing 'private' variables with 'constant' ones - or perhaps merging the two concepts. There is no reason that private variables have to remain the same throughout the life of the object, which is what your friend seems to be implying. const is for unchanging, private is for the object only, they are two very distinct patterns.
Update2
Also, his design falls apart if suddenly your object has more than just a string - and the variables are intertwined (think of a string object, that has a char* and a len, and must be maintained together). The last thing you want is for the user to have to deal with internal variables of an object. Let the object be an object and maintain its own internal values and present a single entity to the user.
I don't see what the benefit of his approach would be.
I personaly prefer to have no fields at all, hence I use auto-implemented private properties instead of private fields and public-get private-set properties if want to have public read-only properties.
If I have to add code to the property, I still only use the field inside of the property accessors and use the getters and setters everywhere else including the constructor.
I have to use fields, too, if I need readonly fields, but C# 4.0 will introduce read-only properties.
Further I would have avoided the whole problem by using the following code.
public static NewObject operator +(NewObject obj1, NewObject obj2)
{
return new NewObject(String.Concat(obj1.Stuff, obj2.Stuff));
}
My prefered implementation would be something like this.
public sealed class NewObject
{
private String Stuff { get; set; }
// Use a method instead of a property because the operation is heavy.
public String GetAllStuff()
{
// Heavy string manipulation of this.Stuff.
return this.Stuff;
}
// Or lets use a property because this.GetAllStuff() is not to heavy.
public String AllStuff
{
get { return this.GetAllStuff(); }
}
public NewObject(String stuffToStartWith)
{
this.Stuff = stuffToStartWith;
}
public static NewObject operator +(NewObject obj1, NewObject obj2)
{
// Error handling goes here.
return new NewObject(String.Concat(obj1.Stuff, obj2.Stuff);
}
}

Categories

Resources