Shouldn't this hashtable be read only? - c#

I have a class that has a getter function for a hashtable called _Parameters.
private Hashtable _Parameters = new Hashtable();
public Hashtable Parameters { get { return _Parameters; } }
_Parameters is not referenced anywhere else in code. Now, since there is no setter function I would think that nothing outside of this class could modify what _Parameters has stored, only read it. However that is not the case. Another class calls this code (where template is an instance of the class mentioned above)
template.Parameters[key] = parameters[key];
This ends up modifying _Parameters. How is this possible? Do setter functions only apply if we are assigning vales with an '='?

No. You're returning a reference, which can be modified. But you can't override the reference itself.
Consider using a ReadOnlyDictionary<TKey, TValue> instead.
Consider reading up on Immutable Objects as well. It should explain the subject to you.

There is a difference between changing the HashTable object or changing the content of the HashTable.
The lack of setter makes sure nobody can:
set the HashTable to NULL
change the reference of the HashTable to another HashTable.
The contents of the HashTable however can be changed.

You can access the methods of the Hashtable, you just can't set it to a new value (such as NULL or a new Hashtable instance).
For example, if I have a List of strings and a Property with a getter but no setter, I can add to the list, remove from the list, call the Clear() method to empty out the list... but I can't do a myList = null (or myList = new List()) because there's no setter.
I'm getting the reference to the object, which allows me to manipulate it, but without a setter I cannot set the reference to a new object.

When you return _Parameters, you're not returning a brand new Hashtable. You're returning another reference to the same one. This one, being a reference to the same object, has the full interface of Hashtable usable on it, including things which modify it. What the lack of a setter does is prevent you from replacing the previous _Parameters with a brand new Hashtable

Having a read only property to a class object (as opposed to a struct) only prevents modifying the value of the property, in this case the object reference. However, when you access the property you get a reference to your internal HashTable object, and you are free to call any public method on the HashTable object returned, including adding and removing entries in the HashTable. What that read only property does is prevent a caller from replacing your HashTable object with a completley different HashTable object.

Related

Return reference not copy with GetValue()

using reflection in c# I need to get only reference to object, not copy, is it possible?
object data = actualData.GetType().GetProperty(properties[0]).GetValue(actualData, null);
variable data should be only reference - if I change something inside, I would like to perform the same changes in actualData variable, but it seems to copy value from actual data and any change stay only in data variable. Any suggestion?
Thanks!
It seems that your property is of value type. Or maybe it is of reference type but it creates a new instance of resulting class instead of reusing it.
If this is a case, then I'm afraid this can't be done in general - properties are methods, so the result value of property is calculated, you cannot observe when that result would be changed.
But if you can change class of which actualData is the instance, then you can implement INotifyPropertyChanged interface and subscribe to its event PropertyChanged in your code.
If this is not possible then you can remember the result of ...GetProperty(), but you have to call GetValue() on it each time when you need the data.

Would "return new Collection<T>(myList)" creates new collection object every time it's called?

Let's say I have a property:
public Collection<T> GameCollection
{
get { return new Collection<T>(_myGameList); }
}
Would this method creates new Collection object every time it's called?
Yes, it would, because of the new. However it does not duplicate myGameList or its contents; it only makes new wrappers for the same myGameList (see Collection(IList<T>) constructor).
If you want to prevent any of that and return a single collection, you can initialize a backing field instead and have your getter get that field (assuming _myGameList is already initialized too):
private Collection<T> _myGameCollection = new Collection<T>(_myGameList);
public Collection<T> GameCollection
{
get { return _myGameCollection; }
}
It would create a new instance of Collection<T>, but each new instance would wrap the same underlying collection. (Per the docs, the constructor overload that takes IList<T> wraps the existing collection.)
So you'd return a new Collection<T> instance every time someone reads the property (which is wasteful and will cause a lot of garbage collection), but it would be returning something that logically acts like the same collection each time.
Yes, it would. When you use the new keyword you always create a new instance.
Yes, it will create a new collection, but that's not as bad as it sounds.
For most types, the new collection only contains references to each item. In other words, it's only about an extra 4 bytes of RAM per object in the collection, rather than the cost of duplicating all the objects. The exception, of course, is value types, but you need to be careful with using those anyway.

List passed by ref - help me explain this behaviour

Take a look at the following program:
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList(myList);
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList(List<int> myList)
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}
I assumed myList would have passed by ref, and the output would
3
4
The list is indeed "passed by ref", but only the sort function takes effect. The following statement myList = myList2; has no effect.
So the output is in fact:
10
50
100
Can you help me explain this behavior? If indeed myList is not passed-by-ref (as it appears from myList = myList2 not taking effect), how does myList.Sort() take effect?
I was assuming even that statement to not take effect and the output to be:
100
50
10
Initially, it can be represented graphically as follow:
Then, the sort is applied myList.Sort();
Finally, when you did: myList' = myList2, you lost the one of the reference but not the original and the collection stayed sorted.
If you use by reference (ref) then myList' and myList will become the same (only one reference).
Note: I use myList' to represent the parameter that you use in ChangeList (because you gave the same name as the original)
You are passing a reference to the list, but your aren't passing the list variable by reference - so when you call ChangeList the value of the variable (i.e. the reference - think "pointer") is copied - and changes to the value of the parameter inside ChangeList aren't seen by TestMethod.
try:
private void ChangeList(ref List<int> myList) {...}
...
ChangeList(ref myList);
This then passes a reference to the local-variable myRef (as declared in TestMethod); now, if you reassign the parameter inside ChangeList you are also reassigning the variable inside TestMethod.
Here is an easy way to understand it
Your List is an object created on heap. The variable myList is a
reference to that object.
In C# you never pass objects, you pass their references by value.
When you access the list object via the passed reference in
ChangeList (while sorting, for example) the original list is changed.
The assignment on the ChangeList method is made to the value of the reference, hence no changes are done to the original list (still on the heap but not referenced on the method variable anymore).
This link will help you in understanding pass by reference in C#.
Basically,when an object of reference type is passed by value to an method, only methods which are available on that object can modify the contents of object.
For example List.sort() method changes List contents but if you assign some other object to same variable, that assignment is local to that method. That is why myList remains unchanged.
If we pass object of reference type by using ref keyword then we can assign some other object to same variable and that changes entire object itself.
(Edit: this is the updated version of the documentation linked above.)
C# just does a shallow copy when it passes by value unless the object in question executes ICloneable (which apparently the List class does not).
What this means is that it copies the List itself, but the references to the objects inside the list remain the same; that is, the pointers continue to reference the same objects as the original List.
If you change the values of the things your new List references, you change the original List also (since it is referencing the same objects). However, you then change what myList references entirely, to a new List, and now only the original List is referencing those integers.
Read the Passing Reference-Type Parameters section from this MSDN article on "Passing Parameters" for more information.
"How do I Clone a Generic List in C#" from StackOverflow talks about how to make a deep copy of a List.
While I agree with what everyone has said above. I have a different take on this code.
Basically you're assigning the new list to the local variable myList not the global.
if you change the signature of ChangeList(List myList) to private void ChangeList() you'll see the output of 3, 4.
Here's my reasoning...
Even though list is passed by reference, think of it as passing a pointer variable by value
When you call ChangeList(myList) you're passing the pointer to (Global)myList. Now this is stored in the (local)myList variable. So now your (local)myList and (global)myList are pointing to the same list.
Now you do a sort => it works because (local)myList is referencing the original (global)myList
Next you create a new list and assign the pointer to that your (local)myList. But as soon as the function exits the (local)myList variable is destroyed.
HTH
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList();
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList()
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}
Use the ref keyword.
Look at the definitive reference here to understand passing parameters.
To be specific, look at this, to understand the behavior of the code.
EDIT: Sort works on the same reference (that is passed by value) and hence the values are ordered. However, assigning a new instance to the parameter won't work because parameter is passed by value, unless you put ref.
Putting ref lets you change the pointer to the reference to a new instance of List in your case. Without ref, you can work on the existing parameter, but can't make it point to something else.
There are two parts of memory allocated for an object of reference type. One in stack and one in heap. The part in stack (aka a pointer) contains reference to the part in heap - where the actual values are stored.
When ref keyword is not use, just a copy of part in stack is created and passed to the method - reference to same part in heap. Therefore if you change something in heap part, those change will stayed. If you change the copied pointer - by assign it to refer to other place in heap - it will not affect to origin pointer outside of the method.

C# object initializers and collections

I'm trying to set up a class so that it's possible to initialize it using an object initializer, but it contains some collections. Ideally I'd like client code to be able to do:
MyClass myObj = new MyClass
{
Name = "Name",
Contents = new[]
{
"Item1",
"Item2"
}
}
However, where Contents needs to be a BindingList<string>. The underlying field stores a readonly reference to this list, and I'd like the setter to essentially do a Clear followed by AddRange to set the contents.
I can't make the Contents property an IEnumerable<string>, because client code wouldn't see the Add method, among many others, at least not without casting it first. I can't make it a BindingList<string> because if I set it, I need to construct a new binding list to pass to it.. this might be possible but I'd rather not introduce the inefficiency of construct a new BindingList<string> solely for the purpose of passing it to the property setter.
The ideal thing to be able to do would be to have the getter return a BindingList<string> and the setter accept IEnumerable<string>, but C# doesn't allow getters/setters on a property to have different types.
Oh, and implicitly casting between BindingList<string> and IEnumerable<string> is a no-no, so I can't do that either (http://blogs.msdn.com/b/peterhal/archive/2005/06/20/430929.aspx).
Is there any way around this?
C# initializer syntax will automatically call the Add method on your property's collection object. That won't call Reset() beforehand of course, but the object is still empty at that point, so it doesn't matter.
Does replacing the list have to use property set syntax? Having a setter replace the content of a collection without actually changing the collection object identity is very unexpected and will likely lead to bugs.
Create a custom collection class that derives from BindingList<string> and add an implicit cast from type string[]
I would recommed encapsulating the BindingList. In this situation go back to the old school way of creating objects so that you aren't creating unnecessary couplings. Favor good OO over language conventions.

problem adding object to hashtable

I am trying to call a class method dynamically depending on a condition. This is how I am doing it
I have three classes implement a single interface
interface IReadFile
{
string DoStuff();
}
The three classes A,B,C implement the interface above.
I am trying to add them to a hashtable with the code below
_HashT.Add("a", new classA());
_HashT.Add("b", new classB());
_HashT.Add("c", new classC());
This compiles fine, but gives a runtime error.{Object reference not set to an instance of an object.}
I was planning to return the correct class to the interface type depending on a parameter that matches the key value. say if I send in a. ClassA is returned to the interface type and the method is called.
IReadFile Obj = (IReadFile )_HashT["a"].GetType();
obj.DoStuff();
How do I correct the part above where the objects need to be added to the hashtable? Or do I need to use a different approach? All the classes are in the same assembly and namespace.
Thanks for your time.
As a guess, you have not instantiated your _HashT object.
You need somewhere in your code (declaration or constructor probably) to instantiate it:
HashTable _HashT = new HashTable();
If you do not do this, _HashT will be null and an attempt to add to it will fail with a NullReferenceException as you have been getting.
It appears you are seeing a NullReferenceException. Based on the limited code you provided I would say it is likely that the _HashT variable is not assigned. It could be possible that the exception is being generated from one of your class constructors as well.
If you use Dictionary<> you can use the following code to add and extract objects from the hashtable.
var hashtable = new Dictionary<IReadFile>();
hashtable.Add("a", new ClassA());
hashtable.Add("b", new ClassB());
hashtable.Add("c", new ClassC());
IReadFile obj = hashtable["a"];
obj.DoStuff();
Following your approach, you do not need to call GetType() on the value you pull out of _HashT. The value should already be an object of type IReadFile.
Why are you calling GetType? The IReadFile object is the thing you are putting in the hash. Casting a Type object into a IReadFile is not going to cast correctly.

Categories

Resources