Visibility inside a class of objects created locally - c#

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.

Related

Remove second reference to object

I got something like the following:
class Factory{
private List<FactorizableObject> _collected; //Collection of all created objects
public FactorizableObject createObject (someParams DontMatter){
FactorizableObject newObject = new FactorizableObject(DontMatter);
_collected.Add(newObject);
return newObject;
}
public void DoSomethingWithCollectedObjects(){
//Work with created objects
}
}
class UsingClass1{
private FactorizableObject myObject;
public UsingClass1(){
myObject = Factory.createObject(someParams);
}
}
class UsingClass2{
private FactorizableObject myObject;
public UsingClass2(){
myObject = Factory.createObject(someOtherParams);
}
}
class WorkingClass{
List<UsingClass1> someOfThese;
List<UsingClass2> someOfThose;
private void triggerWork(){
someOfThese.Remove(RemoveSomeObject);
Factory.DoSomethingWithCollectedObjects();
}
}
Now my Problem is: Even if I remove an instance of a usingClass from on of these lists, the entries in the factory still keep alive and get used when calling DoSomethingWithCollectedObjects. I expected something like a NullreferenceException when trying to work on the object.
The Question: Is there a way to kill the object (the reference to the object) without explicit removing it from the factory-collection? This would need to be done in any class using the factory, so I would like to get around this...
I need some collection like this to perform some special actions on the factorized objects and dont want to care where they are located (The action needs to be done on ALL of the objects). I already tried setting UsingClass1.myObject = null, before removing the object, but this only removed my reference onto the factorized object.

Issue with Treeview item update when passing as a parameter

I have following test code, I am updating m_ClientTreeView by calling createTreeView(TreeView tree) method by passing it. But even treeview is a refrence type, the change is not reflecting back. I checked with ref and it is working properly.
namespace TestRefType
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
ClientGUI objCGUI = new ClientGUI();
createTreeView(objCGUI.m_ClientTreeView);
//createTreeView(ref objCGUI.m_ClientTreeView);
objCGUI.m_ClientTreeView.Dock = DockStyle.Fill;
}
private void createTreeView(TreeView tree)
{
tree = new TreeView();
tree.Visible = false;
}
}
public struct ClientGUI
{
public System.Windows.Forms.TreeView m_ClientTreeView;
}
}
What might be the reason?
Although TreeView is a reference type but it doesn't mean you can change its reference when you pass it to a method.
When you pass a reference type to a method, you can change its members but you can not change reference of object. To change the reference of the object you need to use ref keyword in method signature and when passing the instance to the method.
Without using ref, when you pass objCGUI.m_ClientTreeView to createTreeView(TreeView tree) to method, in the method, tree is just a variable which points to a TreeView. You can access and change tree.SomeProperty, but if you say tree = new TreeView() then you just said the tree variable in your method scope point to a new TreeView. Outside of the method, objCGUI.m_ClientTreeView contains the value which it had before passing to the method.
Example
Here is a really simplified example about what you did:
TreeView t1 = null;
TreeView t2 = t1;
t2 = new TreeView();
What do you expect from t1 now?
Note 1: When using a reference type in a structure, you should be careful when using the structure. Although structures are value type but when copying, their reference types don't copy and keep the same references between different instance of that structure, for example if you add node to the TreeView of the copied structure, the node also will be added to the first instance of your structure.
Note 2: Here is a great article by Joseph Albahari about reference type and value type. It probably will solve most of your problems about the concept:
C# Concepts: Value vs Reference Types

C# creating an array in a singelton class

I want to create an array of Disc which id like to include fields string[] Record, int NumberHeads and string extension. so basically grouping them and instantiate the array once and only once as i dont want more than one of this array in the memory. How can i do this as my fields dont seem to be under the array Disc and if i make them public and run the application i get a null reference exception.
I was initially using a struct but I came to realise these cannot be passed from class to class in C#.
class DiscType
{
private static DiscType[] disc;
private static string[];
public bool discSelect;
public int maxRecord;
public int numberHeads;
public string extension;
public static string[] Record
{
get
{
if (record == null)
{
record = new string[1000];
}
return record;
}
}
public static DiscType[] Disc
{
get
{
if (disc == null)
{
disc = new DiscType[10];
}
return disc;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < DiscType.Disc.Length; i++)
{
DiscType.Disc[i].Record[i]= "1";
}
}
}
If you want only once instanciation of your array do it like that :
public class Singleton
{
private static Singleton instance;
public string[] MyArray { get; set; }
//better using a List<string>
private Singleton() {
//instanciate MyArray here
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
After that you just need to call it like that :
Singleton.intance.MyArray
You describe two problems:
After you think you created a DiscType and an array of records, your array of records only contains null values
Your DiscType is not a singleton.
Is Disctype a singleton?
Someone else already described how to create a Singleton, So I wont write this. However I doubt whether DiscType in your design really is a singleton. If you'd describe your design in words, would you talk about the one and only disctype, or would you say: "Although in my designed world it could be that there were several different disctypes, however because of the huge amount of memory and mabye because of the time it takes to create one, it is advised to use only one disctype during the session".
In the latter case, you should not design it as a singleton. The famous gang of four wrote in their book about design patterns (where the singleton is described) as one of the major rules of design:
Design for change
That means, that you should not restrict your design merely for the case that in the current usage it is not needed. If in your current configuration you only need one disctype, just create only one. If in future versions you need two, you don't need to change your disctype.
So careful review your design: are we talking about "the one and only disctype"? or are we only restricting to one because we don't have enough memory?
Why is my array of records empty
To understand this, you need to know the difference between value types and reference types. Simple types and structs are value types. They exist as soon as you declare them. Instances of classes are always reference types: you need to call new ... to create them. If you don't do this, the value is null.
Myclass X;
string text;
int i;
System.Drawing.Point p; // a Point is a struct!
X and text both have a null value, the only thing you can do with them before you assign something to them is compare them with null
i and p already have a value. You can get them and call their methods.
Back to your problem
Your code:
public static string[] Record
{
get
{
if (record == null)
{
record = new string[1000];
}
return record;
}
}
You assign a newly created object to record. the object is an array of strings, which are reference types. You haven't assigned anything to each string, so each string in your array is still null, and you can't do anything with them until you assign something.
The array of strings however is initialized. You can use methods of the array. You can ask for the length of the array. You can also ask for item[3] in which you get the uninitialized (null) string.
List instead of Array
By the way, this method of initializing is a bit unusual. I guess you don't want to reserve memory for records as long as you don't use them. You would have accomplished that by using List.
My advise is to familiarize yourself with class List. It will make your life so much easier. Before long you'll feel the desire to know all collection classes :-)

The .NET Garbage collector

This is a very basic question. I am debugging some memory leaks and got totally confused. Suppose I have the following:
public class ObjectData : IDataObject
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ObjectRepository<T> where T : IDataObject
{
private Dictionary<int, T> Objects;
public ObjectRepository()
{
Objects = new Dictionary<int, T>();
// load Data
}
public T GetDataObject(int id);
{
return Objects[id];
}
public Reset()
{
Objects = new Dictionary<int, T>();;
}
}
Now suppose I have the following program flow:
public Main()
{
var DataRepository = new ObjectRepository<ObjectData>();
// Constructor called and Data loaded
var myObject = DataRepository.GetDataObject(1);
DataRepository.Reset();
// Call manually the garbage collector or leave it
// Program flow continue after this
}
The question is, will the garbage collector get rid of the collection initially created by the constructor? Or it will not because one of the elements is still referenced in the program flow (myObject)?
It will be collected (eventually), since there is no more references to it. Getting a reference to something in a dictionary doesn't give you any reference to the dictionary itself! Unless that object somehow references the dictionary internally, that is.
To answer such questions ask yourself: Who is referencing the object in question (in this case the overwritten dictionary)?
DataRepository is not. You overwrote the object reference pointing to the old dictionary.
myObject is not because ObjectData does not have any field of type dictionary. It can't reference a dictionary.
Nobody is left to reference the old dictionary.
After your call to Reset, there is no strong references to your initial dictionary. Thus, it will be elected for garbage collection.
Or it will not because one of the elements is still referenced in the program flow (myObject)?
It doesn't matter which objects the dictionary refers to, what matters is who refers to the dictionary. In this case, no one. It's perfectly possible for the dictionary to be collected while its contents are still alive.

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

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.

Categories

Resources