Some kind of creation template needed for C #

I have the following type:

// incomplete class definition public class Person { private string name; public string Name { get { return this.name; } } } 

I want this type to be created and updated with some special controller / builder, but I want it to remain read-only for other types .

This object should also fire an event every time it is updated by its controller / builder.

In the summary, in accordance with the previous skeleton of the type definition:

  • Person can only be created by a specific controller.
  • This controller could update the state of the Person ( name ) field at any time.
  • Person needs to send a notification to all the rest of the world when this happens.
  • All other types must be able to read Person attributes.

How do I implement this? I am talking about a controller / builder here, but all other solutions are welcome.

Note. I could rely on the internal modifier, but ideally all my things should be in the same assembly.

+4
source share
6 answers

Create an IReadOnlyPerson interface that provides access only for access. Ask the person to implement IReadOnlyPerson. Save the link to the Face in your controller. Provide other customers with a read-only version.

This will protect against errors, not fraud, like most OO features. Clients can run time in the Person if they know (or suspect) IReadOnlyPerson is implemented by Person.

Update for comment:

The Read Only interface can also expose an event delegate, like any other object. The idiom commonly used in C # does not prevent clients from communicating with the list of listeners, but the agreement is only to add listeners, so this should be adequate. Inside any accessory or feature set with position-changing side effects, just call the event delegate with protection for the null case (without listeners).

+5
source

I like to have a read-only interface. Then the builder / controller / everything can refer to the object directly, but when you open this object from the outside, you only show the interface.

+1
source

Use the IPerson interface and nested class:

 public class Creator { private class Person : IPerson { public string Name { get; set; } } public IPerson Create(...) ... public void Modify(IPerson person, ...) { Person dude = person as Person; if (dude == null) // wasn't created by this class. else // update the data. } } 
+1
source

I think internal is the least complicated and best approach (this, of course, includes several assemblies). If you are not doing some complicated overhead to determine the caller in the property adjuster, you can try:

 interface IPerson { Name { get; set; } } 

and implement this interface explicitly:

 class Person : IPerson { Name { get; private set; } string IPerson.Name { get { return Name; } set { Name = value; } } } 

then do explicit interface tricks in your builder to set properties. This still does not protect your implementation and is not a good solution, although it does make some way to emphasize your intention.

In your property installers, you will need to do an event notification. Approaching this problem, I did not create separate events and event handlers for each property, but instead I created one PropertyChanged event and fired it in each property when changing (where the event arguments included the property name, old value and new value).

+1
source

It seems strange that although I cannot change the name of the Person object, I can just grab its controller and change it there. This is not the best way to protect your object data.

But despite this, here is a way to do it:

  /// <summary> /// A controlled person. Not production worthy code. /// </summary> public class Person { private string _name; public string Name { get { return _name; } private set { _name = value; OnNameChanged(); } } /// <summary> /// This person controller /// </summary> public PersonController Controller { get { return _controller ?? (_controller = new PersonController(this)); } } private PersonController _controller; /// <summary> /// Fires when <seealso cref="Name"/> changes. Go get the new name yourself. /// </summary> public event EventHandler NameChanged; private void OnNameChanged() { if (NameChanged != null) NameChanged(this, EventArgs.Empty); } /// <summary> /// A Person controller. /// </summary> public class PersonController { Person _slave; public PersonController(Person slave) { _slave = slave; } /// <summary> /// Sets the name on the controlled person. /// </summary> /// <param name="name">The name to set.</param> public void SetName(string name) { _slave.Name = name; } } } 
+1
source

Maybe something like that?

 public class Person { public class Editor { private readonly Person person; public Editor(Person p) { person = p; } public void SetName(string name) { person.name = name; } public static Person Create(string name) { return new Person(name); } } protected string name; public string Name { get { return this.name; } } protected Person(string name) { this.name = name; } } Person p = Person.Editor.Create("John"); Person.Editor e = new Person.Editor(p); e.SetName("Jane"); 

Not really, but I think it works. Alternatively, you can use properties instead of SetX methods in the editor.

0
source

Source: https://habr.com/ru/post/1276821/


All Articles