Make a list / collection of objects with public properties truly readable

I have the 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 am not allowed to change the definition of a class - it is used by other people and they need to write this way. And this is where the problem comes in.

I need static List<Class1> myStaticList

one that can only be changed within class2 and everything else is truly read-only. And by "truly readable" I mean that the user doesn't have to change anything, including the properties of the list items.

Something like: Class2.list[0].pr1="newValue"

called from outside of class2 should be blocked.

ReadOnlyCollection

do not perform tasks because the user can still modify the given list item, so the solution is given here A readonly list <T> with a private set does not satisfy my needs.

Basically, I found many possible ways to make a list / collection read-only (for example IReadOnlyList

), but they all left the ability to change the properties of a given list item if they have a public setter.

The only solution I found was creating a 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 was hoping the two find a better way as it seems strange to me to define an entire new class with just one single read-only list

Thanks in advance for any hints.

Is it possible differently?


The real context looks like this:

In the code, we are editing a database and I want to have a list of backed up records that has been modified with their initial values. I want it to be static so that I can restore the database wherever I want. Class1 contains all the values ​​of a single record in our database, so List<Class1>

I can store all changed records and restore them if necessary. And since this is a backup, it's important to be read-only as unintentional changes can lead to disaster.

+3


source to share


3 answers


In the "I'm not allowed to change it" section, do you mean (as the wording of the question suggests) you are not allowed to change the values ​​in the class? Or are you literally not allowed to change the class declaration itself? Also, if you are not allowed to change the class declaration, what about the code that uses the class in the collections? For example. should the object List<Class1>

continue to remain List<Class1>

, or could you replace the type Class1

with something else?


Without much context, it's hard to know exactly what's best for you. However, one possible approach is to replace Class1

with an interface:

interface IClass1
{
    string str1 { get; }
    string str2 { get; }
}

      

Then declare Class1

as implementing this interface, nested inside Class2

:



class Class2
{
    private class Class1 : IClass1
    {
        public string str1 { get; set; }
        public string str2 { get; set; }
    }
}

      

Now, using the methods you've already seen for creating a read-only list, you are disallowing the replacement of any other elements in the list (i.e. with some other implementation of the interface). And only Class2

can successfully apply the implementation of the item IClass1

in the list before Class1

to access the public network device for properties.

If this does not apply to your problem, it would be helpful if you were more specific as to what the limitations are for solving the problem.

+2


source


Given the fact that you have an approach that works. You are using a solution which is an adapter template. It's not weird to do something like that.

Adapter pattern
Intent
Convert the class interface to another interface.

- Design Patterns (ISBN 0-201-63361-2)

I would define 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've made?



  • so I am not leaking into other assemblies. Thus, other commands cannot be used Class1Adapter

    unless you explicitly allow it.
  • Introduce a new interface IClass1

    . You say you can't change the definition Class1

    , but if it wasn't an API violation, you can pass it to another command. You could, with the current change in definition, Class1

    implement IClass1

    and without any other changes, you could in your code:
var list = new ReadOnlyCollection<IClass1>(source); 

// ... and later, if attempted

list[0].pr1 = "I'm breaking you!"; 

      

Produces:

The property or index 'ConsoleApplication19.IClass1.pr1' has been set to read-only

+2


source


How about Protected ?

https://msdn.microsoft.com/en-us/library/bcd5672a.aspx?f=255&MSPPError=-2147217396

or you can override the setter property.

:)

+1


source







All Articles