Reputation: 31
I have following problem.
Let's say there is a public Class1 defined like this:
public class Class1
{
public string pr1 { get; set; }
public string pr2 { get; set; }
public Class1()
{
}
}
I'm not allowed to modify class definition - it used by other people and they need it written this way. And here comes trouble.
I need static List<Class1> myStaticList
which can be modified only inside Class2 and everywhere else is truly read-only.
And by 'truly read-only' I mean user mustn't change anything including properties of list's elements.
Something like: Class2.list[0].pr1="newValue"
called from outside of Class2 should be blocked.
ReadOnlyCollection
don't do a job because user can still modified given element of a list,
so solution given here List<T> readonly with a private set doesn't satisfy my needs.
Basically I've found a lot of possible ways of making list/collection read-only (e.g. IReadOnlyList
) but all of them left possibility of changing properties of given list element if they have public setter.
The only solution I've found is creating new class:
public class Class1ReadOnly : Class1
{
public new string pr1{ get; private set; }
public new string pr2{ get; private set; }
public Class1ReadOnly(Class1 tmp)
{
pr1= tmp.pr1;
pr2 = tmp.pr2;
}
}
But I hoped two find better way since it seems to me kind of strange to define whole new class just because of one single read-only list
Thanks in advance for any clues.
Is this even possible to this different way?
Real-world context is like this:
In code we edit database and I want to have backup list of records which has been changed with their initial values. I want to have it static just to have possibility of restoring DB everywhere I want. Class1 contains all the values of single record of our DB so by List<Class1>
I can keep all modified records and restore them if it is needed. And since it is backup it is essential to be read-only because unintended change can lead to the disaster.
Upvotes: 3
Views: 632
Reputation: 15415
Given the circumstance you have your approach is one that works. You're using a solution that is the adapter pattern. It is not strange to do something like this.
Adapter Pattern
Intent
Convert the interface of a class into another interface clients expect.
- Design Patterns (ISBN 0-201-63361-2)
I would define such a class like this:
public interface IClass1 {
string pr1 { get; }
string pr2 { get; }
}
internal class Class1Adapter : IClass1 {
public static Class1Adapter FromClass1(Class1 class1) {
var pr1 = class1.pr1;
var pr2 = class1.pr2;
return new Class1Adapter {pr1 = pr1, pr2 = pr2};
}
public string pr1 { get; private set; }
public string pr2 { get; private set; }
}
Why make the choices I did?
Class1Adapter
unless you explicitly let it out. IClass1
. You say you are not able to change the definition of Class1
, but if it wasn't an API breaking change... you might be able to pitch it to the other team. You could with the current definition change Class1
to implement IClass1
and with no other changes, you could in your code: var list = new ReadOnlyCollection<IClass1>(source);
// ... and later, if attempted
list[0].pr1 = "I'm breaking you!";
Would produce:
Property or indexer 'ConsoleApplication19.IClass1.pr1' cannot be assigned to -- it is read only
Upvotes: 2
Reputation: 70652
By "I'm not allowed to change it", do you mean that (as the question wording implies) you are not allowed to modify the values in the class? Or that you literally are not allowed to modify the class declaration itself? Also, if you are not allowed to modify the class declaration, what about the code that uses the class in collections? E.g. would a List<Class1>
object be required to continue to be a List<Class1>
, or could you replace the Class1
type with something else?
Without more context, it is difficult to know for sure what is best in your case. However, one possible approach is for Class1
to be replaced by an interface:
interface IClass1
{
string str1 { get; }
string str2 { get; }
}
Then declare Class1
as implementing that interface, nested inside Class2
:
class Class2
{
private class Class1 : IClass1
{
public string str1 { get; set; }
public string str2 { get; set; }
}
}
Now, using the techniques you've already seen for making the list itself read-only, you prevent any other code from replacing elements within the list (i.e. with some other implementation of the interface). And only Class2
can successfully cast the implementation of the IClass1
element in the list to Class1
to gain access to the public setter for the properties.
If that doesn't address your concern, it would be helpful if you could be more specific about exactly what constraints exist for solving the problem.
Upvotes: 2
Reputation: 508
How about Protected set?
https://msdn.microsoft.com/en-us/library/bcd5672a.aspx?f=255&MSPPError=-2147217396
or you can override property setter.
:)
Upvotes: 1