I have a class with various public properties which I allow users to edit through a property grid. For persistence this class is also serialized/deserialized to/from an XML file through DataContractSerializer.
Sometimes I want to user to be able to save (serialize) changes they've made to an instance of the class. Yet at other times I don't want to allow the user to save their changes, and should instead see all the properties in the property grid as read only. I don't want to allow users to make changes that they'll never be able to save later. Similar to how MS Word will allow users to open documents that are currently opened by someone else but only as read only.
My class has a boolean property that determines if the class should be read-only, but is it possible to use this property to somehow dynamically add a read-only attributes to the class properties at run-time? If not what is an alternative solution? Should I wrap my class in a read-only wrapper class?
Why not something like:
You can not get compile-time checks (like given with the keyword
readonly
) by changing a property to readonly at runtime. So there is no other way, as to check manually and throw an exception.But propably it is better to re-design access to the class. For example create a "writer class", which checks if the underling "data class" can currently be written or not.
If you are creating a library, it is possible to define a public interface with a private/internal class. Any method which needs to return an instance of your read-only class to an external consumer should instead return an instance of the read-only interface instead. Now, down-casting to a concrete type is impossible since the type isn't publicly exposed.
Utility Library
Your Library
Now, anyone who uses
SomeClass
will get back what looks like two different objects. Of course, they could use reflection to see the underlying types, which would tell them that this is really the same object with the same type. But the definition of that type is private in an external library. At this point, it is still technically possible to get at the definition, but it requires Heavy Wizardry to pull off.Depending on your project, you could combine the above libraries into one. There is nothing preventing that; just don't include the above code in whatever DLL you want to restrict the permissions of.
Credit to XKCD for the comments.
I would use a wrapper class that keeps everything read-only. This is for scalability, reliability and general readability.
I do not foresee any other methods of doing this that will provide the above three mentioned benefits as well as something more. Definitely use a wrapper class here in my opinion.
Would something like this help:
You need to catch exceptions when setting properties.
I hope this is something you are looking for.
Immutability is an area where C# still has room to improve. While creating simple immutable types with
readonly
properties is possible, once you need more sophisticated control over when type are mutable you start running into obstacles.There are three choices that you have, depending on how strongly you need to "enforce" read-only behavior:
Use a read-only flag in your type (like you're doing) and let the caller be responsible for not attempting to change properties on the type - if a write attempt is made, throw an exception.
Create a read-only interface and have your type implement it. This way you can pass the type via that interface to code that should only perform reads.
Create a wrapper class that aggregates your type and only exposes read operations.
The first option is often the easiest, in that it can require less refactoring of existing code, but offers the least opportunity for the author of a type to inform consumers when an instance is immutable vs when it is not. This option also offers the least support from the compiler in detecting inappropriate use - and relegates error detection to runtime.
The second option is convenient, since implementing an interface is possible without much refactoring effort. Unfortunately, callers can still cast to the underlying type and attempt to write against it. Often, this option is combined with a read-only flag to ensure the immutability is not violated.
The third option is the strongest, as far as enforcement goes, but it can result in duplication of code and is more of a refactoring effort. Often, it's useful to combine option 2 and 3, to make the relationship between the read-only wrapper and the mutable type polymorphic.
Personally, I tend to perfer the third option when writing new code where I expect to need to enforce immutability. I like the fact that it's impossible to "cast-away" the immutable wrapper, and it often allows you to avoid writing messy if-read-only-throw-exception checks into every setter.