3

Let's say I have a simple class which contains a bunch of attributes or properties:

internal class ConnectionProperties { internal string Name = "Default Name"; internal bool Enabled = false; } 

And these are used within a class called Data:

internal class Data { private ConnectionProperties _connection; internal Data() { this._connection = new ConnectionProperties(); // Business logic to configure connection this._connection.Name = "My Connection"; this._connection.Enabled = true; _ } } 

How can I allow external access to the properties and values of _connection WITHOUT allowing them to be changed from anywhere apart from the class Data.

I know I could add a property such as

internal ConnectionName => _connection.Name; 

But that feels very messy and could be tough to maintain

3
  • The best way to encapsulate the properties of your object is by using constructor which creates the object in its full and valid state and them expose what ever you need by readonly properties. Commented Jan 4, 2020 at 15:36
  • @vasiloreshenski My problem is that I'm happy for the ConnectionProperties class to get changed and configured as time goes on, but I don't want anything messing up the Data Classes instance of it Commented Jan 4, 2020 at 15:38
  • Well you can inherit ConnectionProperties from interface which exposes the the properties in readonly manner. The ConnectionProperties class will remain the same and in the Data class expose the ConnectionProperties class by the interface. Commented Jan 4, 2020 at 15:44

3 Answers 3

4

If you control the ConnectionProperties type, you can make it implement an interface, say IReadOnlyConnectionProperties, that will expose a readonly view of its members.

public interface IReadOnlyConnectionProperties { string Name { get; } bool Enabled { get; } } 

If you don't control the type, you can make such an interface and create a wrapper type that will implement it. It would take ConnectionProperties in its ctor and proxy get-accesses to it properties. The same way a ReadOnlyCollection does.

internal ReadOnlyConnectionProperties : IReadOnlyConnectionProperties { private readonly ConnectionProperties _wrapped; public string Name => _wrapped.Name; public bool Enabled => _wrapped.Enabled; public ReadOnlyConnectionProperties( ConnectionProperties connectionProperties) => _wrapped = connectionProperties; } 

Note that this assumes a level of trust to the user. If using the first solution, there's nothing stopping the consumers from upcasting the interface back to ConnectionProperties. The second solution avoids this problem, and is the one I'd recommend. Just remember that in both cases changes to the underlying ConnectionProperties will be reflected in whatever proxies you give to your consumers.

Sign up to request clarification or add additional context in comments.

Comments

1

You can create something like readonly interface for the ConnectionProperties class and expose it in the Data class by the readonly interface. This way the ConnectionProprties will have the same functionality.

 internal interface IConnectionProperties { string Name { get; } bool Enabled { get; } } internal class ConnectionProperties : IConnectionProperties { public string Name { get; set; } = "Default Name"; public bool Enabled { get; set; } = false; } internal class Data { private ConnectionProperties _connection; internal IConnectionProperties Connection => this._connection; } 

The only change is that you need to make the ConnectionProperties's class properties public - Name, Enabled.

Comments

1

You can have read only properties inside your class like this with different levels of encapsulation.

public string Name{get;} With this you are only able to set the Name only inside the constructor of ConnectionProperties class.

public string Name{get;private set;} With this you are only able to set the Name anywhere inside the ConnectionProperties class and not anywhere else.

public string Name{get;internal set;} With this you are only able to set the Name anywhere inside the dll not allowing other dlls to set its property.

It all starts from your ConnectionProperties on how other classes view it.

Here is how I would solve your example.

public class Program { public static void Main(string[] args) { var data = new Data(); var c = new ConnectionProperties("", false); data.Connection.Name = ""; // prints readonly error data.Connection = new ConnectionProperties("", false); //prints readonly error data.Connection = c; //prints readonly error } } internal class ConnectionProperties { internal ConnectionProperties(string name, bool enabled) { Name = name; Enabled = enabled; } internal string Name { get; } internal bool Enabled { get; } } internal class Data { public ConnectionProperties Connection => new ConnectionProperties("My Connection", true); internal Data() { } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.