How do I prevent dictionary items from modification outside of my class?
I have to expose collection of objects as a property, but then everyone can do everything with my objects. I tried to use ReadOnlyDictionary to wrap my public property, but IntegerValue property still can be modified from outside.
Sample code is below:
internal class MyRefClass
{
public object ReferenceStrig;
public int IntegerValue;
public MyRefClass()
{
ReferenceStrig = "Initialized string";
IntegerValue = 100;
}
}
class Program
{
static void Main(string[] args)
{
var writableDict = new Dictionary<int, MyRefClass>();
writableDict.Add(1,new MyRefClass());
ReadOnlyDictionary<int, MyRefClass> dict = new ReadOnlyDictionary<int, MyRefClass>(writableDict);
MyRefClass variable;
dict.TryGetValue(1, out variable); #get an object from dictionary
variable.IntegerValue = 0; #changing property of the object
writableDict.TryGetValue(1, out variable); #get the same object once again
#now property variable.IntegerValue == 0 instead of 100!
}
}
If you want to expose an object to "Client code" and yet you want the object not to be modified then you must return a "Immutable type". Either in the form of immutable class or an interface with only readonly properties.
This also means that all the properties and nested properties and so on of your type should also be "Immutable" otheriwse they will be still able to modify the nested members. In other words All types in object graph of the type you expose must be Immutable.
Another option is to clone the object and return the copy and forget about the modifications. But be sure you're doing a Deep-Copy and not Shallow-Copy. Shallow copy suffers from aforementioned problem.
Make your class immutable, for example:
class MyImmutableRefClass
{
public readonly object ReferenceStrig;
public readonly int IntegerValue;
public MyImmutableRefClass(): this("Initialized string", 100)
{
}
public MyImmutableRefClass(string referenceStrig, int integerValue)
{
ReferenceStrig = referenceStrig;
IntegerValue = integerValue;
}
}
This isn't really enough if ReferenceStrig is an object which itself isn't immutable. It works for this particular example because it can only be a string (which is itself immutable).
But if it was some other type, then that type would have to be immutable itself - and (recursively) any public fields and properties that it contains would also have to be immutable. (I call that "deep-immutable".)
Here's an interesting series of articles on immutability in C#:
http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx
Related
I'm trying to access a field from a derived class in an array that holds references to the base class.
I have three classes:
abstract GameObjectBase
{
}
And derived from that are:
public Gamespace: GameObjectBase
{
private bool containsItem;
}
And:
public GameWall: GameObjectBase
{
}
(Obviously these classes hold more data, methods, and constructors).
I have created an array from these objects, like this
private GameObjectBase[,] _labyrinthArray = new GameObjectBase[10,10];
I then fill said array with Gamespaces and Gamewalls. But when I access a Gamespace object in the array, the containsItem field is not accessible due to the reference to the object being of type GameObjectBase.
Obviously I could put containsItem in GameObjectBase and make it accessible from there, but that doesn't fit my OOP approach. The only other solution I have found is to cast the object in question explicitely to Gamespace.
That seems quite crude and error prone to me. Is there any better solution to this?
First of all, you cannot reference a private field from outside the object class itself. You probably want to use a read-only property to encapsulate the field. If you don't want to cast the object explicitly to a Gamespace, you could use an interface instead.
public interface ICanContainItem
{
bool ContainsItem { get; }
}
public class Gamespace : GameObjectBase, ICanContainItem
{
private bool _containsItem;
public bool ContainsItem
{
get { return _containsItem; }
private set { _containsItem = value; }
}
}
This way you can then check whether the object "can contain an item" or not through the interface. Even if in the future you add new types of spaces that can contain an item, this same piece of code works, if the new types also implement the same interface.
var gameObject = _labyrinthArray[i,j]; //i,j defined elsewhere
var mayContainItem = gameObject as ICanContainItem;
if (mayContainItem != null)
{
var itemExists = mayContainItem.ContainsItem;
//mayContainItem.ContainsItem = false; //<-- fails because there's no setter
}
I'm trying using ReadOnlyCollection to make object immutable, I want the property of object are immutable.
public ReadOnlyCollection<FooObject> MyReadOnlyList
{
get
{
return new ReadOnlyCollection<FooObject>(_myDataList);
}
}
But I little confused.
I tried to change the property of the object in to MyReadOnlyList using a foreach and ... I can change value property, is it correct? I understood ReadOnlyCollection set an add level to make the object immutable.
The fact that ReadOnlyCollection is immutable means that the collection cannot be modified, i.e. no objects can be added or removed from the collection. This does not mean that the objects it contains immutable.
This article by Eric Lippert, explains how different kinds of immutability work. Basically, a ReadOnlyCollection is an immutable facade which can read the underlying collection (_myDataList), but cannot modify it. However, you can still change the underlying collection since you have a reference to _myDataList by doing something like _myDataList[0] = null.
Furthermore, the objects returned by ReadOnlyCollection are the same ones returned by _myDataList, i.e. this._myDataList.First() == this.MyReadOnlyList.First() (with LINQ). This means that if an object in _myDataList is mutable, then so is the object in MyReadOnlyList.
If you want the objects to be immutable, you should design them accordingly. For instance, you might use:
public struct Point
{
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
// In C#6, the "private set;" can be removed
public int X { get; private set; }
public int Y { get; private set; }
}
instead of:
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
Edit: in this case, as noted by Ian Goldby, neither struct allows you to modify properties of the elements in the collection. This happens because structs are value types and when you access an element the collection returns a copy of the value. You can only modify the properties of a Point type if it is a class, which would mean that references to the actual objects are returned, instead of copies of their values.
I tried to change the property of the object in to MyReadOnlyList
using a foreach and ... I can change value property, is it correct? I
understood ReadOnlyCollection set an add level to make the object
immutable.
Using a ReadOnlyCollection does not make any guarantees as for the object that is stored in the collection. All it guarantees is that the collection cannot be modified once it has been created. If an element is retrieved from it, and it has mutable properties, it can very well be modified.
If you want to make your FooObject an immutable one, then simply do so:
public class FooObject
{
public FooObject(string someString, int someInt)
{
SomeString = someString;
SomeInt = someInt;
}
public string SomeString { get; };
public int SomeInt { get; };
}
What is immutable is the collection itself, not the objects. For now, C# doesn't support immutable objects without wrapping them as ReadOnlyCollection<T> does in your case.
Well, you can still create immutable objects if their properties have no accessible setter. BTW, they're not immutable at all because they can mutate from a class member that may have equal or more accessibility than the setter.
// Case 1
public class A
{
public string Name { get; private set; }
public void DoStuff()
{
Name = "Whatever";
}
}
// Case 2
public class A
{
// This property will be settable unless the code accessing it
// lives outside the assembly where A is contained...
public string Name { get; internal set; }
}
// Case 3
public class A
{
// This property will be settable in derived classes...
public string Name { get; protected set; }
}
// Case 4: readonly fields is the nearest way to design an immutable object
public class A
{
public readonly string Text = "Hello world";
}
As I said before, reference types are always mutable by definition and they can behave as immutable under certain conditions playing with member accessibility.
Finally, structs are immutable but they're value types and they shouldn't be used just because they can represent immutable data. See this Q&A to learn more about why structs are immutable: Why are C# structs immutable?
Maybe it's just a misunderstanding but this is a big question for me. Let me explain it:
According to reference a property is a mechanism and not a field. A mechanism that provide read and write functions for a field, and according to this we can create a read-only, write-only or read-write property by using get and set accessors.
Now the implementation is here:
public class Foo
{
private List<string> _bar;
public List<string> Bar
{
get
{
return _bar;
}
}
public Foo()
{
_bar = new List<string>();
_bar.Add("string1");
}
}
In Foo class we have a read-only property (Bar) that consists of one string.
Now lets add a driver for this class:
static void Main(string[] args)
{
Foo fooObj = new Foo();
fooObj.Bar.Add("string2");
foreach (string s in fooObj.Bar)
{
Console.WriteLine(s);
}
Console.ReadLine();
}
And here is the big question mark:
Why the Bar property is not read-only?
output:
srring1
string2
I know how to create a read-only collection (my question is not why List<T> is not read-only) and I need a explanation about read-only properties.
Well the Bar property is read only i.e. it can't be directly set
fooObj.Bar = new List<string>(); // compiler error
However, the data returned by that property isn't
fooObj.Bar.Add("..."); // is fine
The point to understand is the modifier on a property dictates how it can be accessed from the object, it has no direct affect on the underlying data of the property. Therefore, returning a reference type from a read-only property is the exact same as returning a reference type from a read/write property.
In your example, if you wanted the Bar to be read-only then you could return a ReadOnlyCollection<T> which is an immutable collection, rather than a List<T>.
private List<string> _bar;
...
public void Add(string item)
{
_bar.Add(item);
}
public IEnumerable<string> Bar
{
get { return new ReadOnlyCollection<string>(_bar); }
}
This would keep control of the list with the containing object but allow you to return a readonly copy of the list itself.
Okay,
A List<T> is a reference type.
So, a property
List<string> SomeList
{
get
{
// ...
}
}
is a read-only property, you cannot set the SomeList to a different List<string>. Essentially,
SomeList = new List<string>();
will not compile.
As you note, making a property of a reference type read only does not make that type read only.
If you want a read only list I'd suggest,
IReadOnlyList<string> SomeList
{
get
{
// ...
}
}
Because the getter method of your Bar property returns the list, and then you are mutating that list.Omitting the setter method only prevents you to assign a new list directly like this:
fooObj.Bar = new List<string>();
If you want to make it immutable you can change return type of your property to IEnumerable<string> instead.. Though you can still cast it to list and then mutate...
The Bar property is read-only. You can only read the list Bar points to - you cannot make Bar point to some other list.
However, the list itself is mutable. You can add or remove items from it.
Eric lippert calls this "shallow immutability" in his blog post Immutability in C# Part One: Kinds of Immutability. The property is read-only, but its contents can change.
Consider the class:
public class foo
{
public object newObject
{
get
{
return new object();
}
}
}
According to MSDN:
Properties are members that provide a flexible mechanism to read,
write, or compute the values of private fields. Properties can be used
as though they are public data members, but they are actually special
methods called accessors. This enables data to be accessed easily
And:
Properties enable a class to expose a public way of getting and
setting values, while hiding implementation or verification code.
A get property accessor is used to return the property value, and a
set accessor is used to assign a new value. These accessors can have
different access levels. For more information, see Accessor
Accessibility.
The value keyword is used to define the value being assigned by the
set indexer.
Properties that do not implement a set method are read only.
while still providing the safety and flexibility of methods.
Does this therefore mean that at some point in time the value of the newObject property has a reference to the returned new object?
edit removed readonly from property
edit2 also would like to clarify that this is not the best use for a property but its done to try and illustrate the question more effectively.
You return a new object on each access to the property and that is not the expected behavior of properties. Instead you should return the same value each time (e.g. a value stored in a field). A property getter is simply glorified syntax for a method that returns a value. Your code compiles into something like this (the compiler creates a getter by prefixing the property name with get_ which is then emitted as IL):
public class foo
{
public object get_newObject()
{
return new object();
}
}
Each call to the getter will create a new object that foo doesn't know about or has access to.
Does this therefore mean that at some point in time the value of the newObject property has a reference to the returned new object?
No.
Property using a backing field:
class Foo {
readonly Object bar = new Object();
public Object Bar { get { return this.bar; } }
}
Using automatic properties:
class Foo {
public Foo() {
Bar = new Object();
}
public Object Bar { get; private set; }
}
A property is accessed using the same easy syntax as a public field. However, by using a property you can add code to the getter and the setter allowing you to do stuff like lazy loading in the getter or validation in the setter (and much more).
Under the hood, your property will simply be calling a function named get_newObject() that looks like this:
public object get_newObject()
{
return new object();
}
Since that is the case, it will always return a new object every time it is invoked.
If you want to retain a reference to the object, then I would recommend creating a private field to hold the data and having the property access that field, like so:
private object myObject;
public object newObject
{
if(myObject == null)
{
myObject = new object();
}
return myObject;
}
Since your property doesn't define set, and your field is private, newObject is basically eradonly outside of the containing class.
Properties in C# are "syntactic sugar". The code within the get block of a property is in fact put into a hidden get_PropertyName() method, and the set block into a hidden set_PropertyName() method. In the case of your code, the following method will be created:
public object get_newObject()
{
return new object();
}
You can see these hidden methods if you view the compiled assembly using Reflector, or ildasm.
When the property is used, the C# compiler converts any "get" accesses of your property into calls of the get_newObject() method. As an example:
If you were to write the following:
var foo = new foo();
var aNewObject = foo.newObject;
The compiler would convert that to:
var foo = new foo();
var aNewObject = foo.get_newObject();
So, in answer to your other question, the newly created object returned when someone "gets" the property won't be stored within your foo instance, the caller will simply get a new object every time.
Not exactly. Properties are just syntactic sugar so that you don't have to write accessor methods (like Java).
So this:
private int _myInteger;
public int MyInteger
{
get { return _myInteger; }
set { _myInteger = value; }
}
is equivilant to this:
private int _myInteger;
public int GetMyInteger()
{
return _myInteger;
}
public void SetMyInteger(int value)
{
_myInteger = value;
}
and it gets better with this, which is also equivilant:
public int MyInteger { get; set; }
What would be the best way to write a generic copy constructor function for my c# classes?
They all inherit from an abstract base class so I could use reflection to map the properties, but I'm wondering if there's a better way?
A copy constructor basically means you have a single parameter, which is the object you're going to copy.
Also, do a deep copy, not a shallow copy.
If you don't know what deep and shallow copies are, then here's the deal:
Suppose you're copying a class that has a single row of integers as field.
A shallow copy would be:
public class Myclass()
{
private int[] row;
public MyClass(MyClass class)
{
this.row = class.row
}
}
deep copy is:
public class Myclass()
{
private int[] row;
public MyClass(MyClass class)
{
for(int i = 0; i<class.row.Length;i++)
{
this.row[i] = class.row[i];
}
}
}
A deep copy really gets the actuall values and puts them in a new field of the new object, whilst a shallow copy only copies the pointers.
With the shallow copy, if you set:
row[3] = 5;
And then print both rows, both prints will have 5 as value of the 4th number.
With a deep copy however, only the first print will have this, since the rows don't have the same pointers.
Avoid reflection if you can. Each class should have the responsibility of copying its own properties, and send it further to the base method.
You can create a shallow copy efficiently with reflection by pre-compiling it, for example with Expression. For example, like so.
For deep copies, serialization is the most reliable approach.
Here's a constructor that I'm using. Note that this is a shallow constructor, and rather simplistic, due to the nature of my base class. Should be good enough to get you started.
public partial class LocationView : Location
{
public LocationView() {}
// base class copy constructor
public LocationView(Location value) {
Type t = typeof(Location);
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo pi in properties)
{
pi.SetValue(this, pi.GetValue(value, null), null);
}
}
public Quote Quote { get; set; }
}
You may reference valueinjecter and fasterflect nuget packages and use:
public class Myclass()
{
private string _property;
public MyClass(MyClass obj)
{
this.InjectFrom(obj.DeepClone());
}
}