Making collection items read only - c#

I have a business entities as below,
class Class1
{
List<Class2> classes = new List<Class2>();
public IEnumerable<Class2> Classes { get { return classes.AsEnumrable(); }
public void AddClass(Class2 cls)
{
classes.Add(cls);
}
}
class Class2
{
public string Property { get; set; }
}
My business logic requires that once a Class2 instance is added using the AddClass method to the top of the Classes list in Class1, no one should be able to edit the properties of the Class2 instances added previously to the list, only the last item in the list could be edited. How do I do this?
I have tried IReadOnlyList, but it appears that it is concerned with making the list structure itself uneditable without preventing the edit of its items' content.

It's not a container's job to dictate the behavior of its items. A container is just that - an object that contains other objects. An IReadOnlyList is a container whose items cannot be modified. But the items within it are jsut Class2 instances - there's nothing that the container can do to prevent them from being edited.
Consider this:
myReadOnlyCollection[0].Property = "blah";
var firstItem = myReadOnlyCollection[0];
firstItem.Property = "blah";
Should this be legal in your scenario? What's the difference between the two? firstItem is simply an instance of Class2 that has no idea it was once inside a read-only collection.
What you need is for Class2 itself to be immutable. That's up to the class, not the container. Read up on immutability, which is an important concept to grasp, and implement Class2 accordingly. If you need a regular, mutable Class2 to change its behavior, perhaps add a ToImmutable() method to it which returns a different item, without a setter.

Why are you exposing the IReadOnlyCollection. Once you have exposed the objects, the objects themselves have to be immutable.
Why not just expose the only object that you want to expose?
private IEnumerable<Class2> Classes { get { return classes; }
public Class2 Class2Instance { get { return classes.Last(); } }

I can only see three options. One is to alter Class2 to make it lockable and then lock it once it's added to your list...
class Class1 {
List<Class2> classes = new List<Class2>();
public IEnumerable<Class2> Classes {
get { return classes.AsEnumrable();
}
public void AddClass(Class2 cls) {
cls.Lock();
classes.Add(cls);
}
}
class Class2 {
private string _property;
private bool _locked;
public string Property {
get { return _property; }
set {
if(_locked) throw new AccessViolationException();
_property = value;
}
}
public void Lock() {
_locked = true;
}
}
Another option is to only return the values of the list objects instead of the objects themselves...
class Class1 {
List<Class2> classes = new List<Class2>();
public IEnumerable<string> Values {
get { return classes.Select(cls => cls.Property); }
}
public void AddClass(Class2 cls) {
classes.Add(cls);
}
}
In this second method, anything other than a single value and you'll need to either return a tuple. Alternately, you could create a specific container for Class2 that exposes the values as read-only...
class Class2ReadOnly {
private Class2 _master;
public Class2ReadOnly(Class2 master) {
_master = master;
}
public string Property {
get { return _master.Property; }
}
}
class Class1 {
List<Class2ReadOnly> classes = new List<Class2ReadOnly>();
public IEnumerable<Class2ReadOnly> Classes {
get { return classes.AsEnumerable(); }
}
public void AddClass(Class2 cls) {
classes.Add(new Class2ReadOnly(cls));
}
}

I know it is an old problem, however I faced the same issue today.
Background: I want to store data in my application, e.g. users can set their custom objects in the project and the Undo-redo mechanism must be adapted to handle batched data storing.
My approach:
I created some interfaces, and I made a wrapper for the collection I don't want the users to modify.
public class Repository : IRepository
{
// These items still can be changed via Items[0].CustomProperty = "asd"
public readonly List<CustomItem> Items { get; }
private readonly List<CustomItem> m_Originaltems;
//However, when I create RepositoryObject, I create a shadow copy of the Items collection
public Repository(List<CustomItem> items)
{
items.ForEach((item) =>
{
// By cloning an item you can make sure that any change to it can be easily discarded
Items.Add((CustomItem)item.Clone());
});
// As a private field we can manage the original collection without taking into account any unintended modification
m_OriginalItems = items;
}
// Adding a new item works with the original collection
public void AddItem(CustomItem item)
{
m_OriginalItems.Add(item);
}
// Of course you have to implement all the necessary methods you want to use (e.g. Replace, Remove, Insert and so on)
}
Pros:
Using this approach you basically just wraps the collection into a custom object. The only thing you expect from the user side is to have ICloneable interface implemented.
If you want, you can make your wrapper generic as well, and give a constraint like where T : ICloneable
Cons:
If you add new items, you won't know about them by checking the Items property. A workaround can be done by creating a copy of the collection whenever Items.get() is called. It is up to you and your requirements.
I meant something like this:
public class Repository : IRepository
{
public List<CustomItem> Items => m_OriginalItems.Select(item => (CustomItem)item.Clone()).ToList();
private readonly List<CustomItem> m_Originaltems;
public Repository(List<CustomItem> items)
{
m_OriginalItems = items;
}
public void AddItem(CustomItem item)
{
m_OriginalItems.Add(item);
}
// Of course you still have to implement all the necessary methods you want to use (e.g. Replace, Count, and so on)
}

As other said, it is not the collections job to dictate if (and how) you access it's elements. I do see ways around this:
Exceptions & references:
Modify Class2 so it can take a reference to Class1. If the reference is set, throw excetpions on all setters. Modify Class1.AddClass to set that property.
A softer version of this would be a "read only" property on Class2, that all other code has to check.
Readonly Properties & Constructors:
Just always give Class2 readonly properties (private set). If you want to define the property values, you have to do that in the constructor (which has proper Arguments). This pattern is used heavily by the Exception classes.
Inheritance Shenanigans:
Make Multiple Class2 versions in an inheritance chain, so that that Class2Writebale can be cast to a Class2ReadOnly.
Accept the wrong Y:
You might have stuck yourself into a XY problem: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem
If so go a step back to fix it.

Related

C# Read attributes from Generic class without instance

Problem Description
I'm trying to implement a very specific sort of cache of objects that I may not be able to instantiate directly (private constructors for instance)
What I want to do is read some information about the particular class, preferably through some kind of interface (which sadly doesn't support static methods defined for every subclass)
In other words:
public class Data
{
public static bool Attribute1() => False;
private Data(...) { ... }
}
public class Cache<T> // T is for instance Data
{
void SomeMethod()
{
bool Value = T.Attribute1()
...
}
}
It's fine if I can make T inherit from some base class or some interface, and to get the attribute through some sort of method or directly. It is very important though that I can
Program multiple data classes A and B, where A.Attribute1() is different from B.Attribute1()
Get the attribute from the data class type without instantiating the data type
Current Solution
I do currently have a solution in the shape of a registry built when the static objects are initialised, like this:
class CacheAttributesRegistry
{
static RegisterAttributes(Type T, bool Attribute1, ...) { ... }
}
class Data
{
static Data() { RegisterAttributes(typeof(Data), true, ...); }
}
class Cache<T>
{
void SomeMethod()
{
bool Value = CacheAttributesRegistry.Attribute1(typeof(T));
}
}
It does exactly what I want, but I'd prefer avoiding a static constructor in every data class, also I don't want it to be possible to accidentally call RegisterAttributes at runtime.
Preferably I'd also avoid reflection because I'd like it to be obvious how to set the attributes for a class without the code magically inferring it in the background.
Am I missing some option or have I just reached some language limitations?

Sharing dependency property in C# (WPF) between two classes

I want two share a DepedencyProperty between to classes using AddOwner (any other approach is welcome), e.g.
class ClassA : DependencyObject
{
public int Number
{
get { return (int)GetValue(NumberProperty); }
set { SetValue(NumberProperty, value); }
}
public static readonly DependencyProperty NumberProperty =
DependencyProperty.Register("Number", typeof(int), typeof(ClassA),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.Inherits));
}
and
class ClassB : DependencyObject
{
public int Number
{
get { return (int)GetValue(NumberProperty); }
set { SetValue(NumberProperty, value); }
}
public static readonly DependencyProperty NumberProperty =
ClassA.NumberProperty.AddOwner(typeof(ClassB),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.Inherits));
}
like described here. As you might guess: Of course it doesn't work. That makes perfect sense, because it would make it impossible to create multiple instances of the same class that all have their "own" dependency property.
How do I make sure that all classes (and especially all instances) of ClassA, ClassB and any other class which refers to the property are talking about the exact same property (and therefore value)? A Singleton is no option, since Class A is a MainWindow and Class B is an UserControl (protected constructors are therefore not possible).
Regards,
Ben
I think you're misunderstanding the purpose of DependencyProperties.
They are basically a Property Definition, without a property Value.
They define things like name, type, default value, location of the value, etc however they do not contain the actual value itself. This allows the value to be provided with a binding pointing to any other property in any other location.
Your best bet is to probably just create a property that is backed by a singleton property.
public int Number
{
get { return MySingleton.Number; }
set { MySingleton.Number = value; }
}
Edit
Based on comments below where you say you want all instances of the object to respond to change notifications from any of the other objects, you'd want to implement INotifyPropertyChanged on your singleton object, and subscribe to it's PropertyChange event in each class that uses that value.
For example,
public ClassA
{
public ClassA()
{
MySingleton.PropertyChanged += Singleton_PropertyChanged;
}
void Singleton_PropertyChanged(object sender, NotifyPropertyChangedEventArgs e)
{
// if singleton's Number property changed, raise change
// notification for this class's Number property too
if (e.PropertyName == "Number")
OnPropertyChanged("Number");
}
public int Number
{
get { return MySingleton.Number; }
set { MySingleton.Number = value; }
}
}
One possible solution to what you want here is to use another class where you store that
value. e.g.
public class SomeValueStore : IValueStore
{
int myValue {get; set;}
}
Then, whereever you need that value, you can use Dependency injection to get it.
somewhere at Bootstrapper:
RootContainer.Register<IValueStore>(new SomeValueStore);
and in code:
var valueStore = RootContainer.Resolve<IValueStore();
valueStore.myValue = 42;
This is just an idea (And I know we have a ServiceLocator here).
Perhaps you can store a reference to that ValueStore somewhere where you
can get it from both classes you need it as a simple solution.
public SomeClassYouHaveAccessToFromBothSides
{
public IValueStore _store = new SomeValueStore();
}
Please excuse me. I do not have access to my repo / visual studio right now
so I cannot give better example. But I think the underlying idea is clear.

Is there a good pattern for exposing a generic collection as readonly?

So I've got these classes that expose a collection of child objects.
I don't want other classes adding or removing objects from collections because I need to wire into events in the child objects, so as they get added or removed I want to be able to do additional processing. But I really love the ease of manipulating generics internally.
Did I mention this is a WPF app so I need INotifySupport?
The best I can come up with is something like this.
public class foo : INotifyPropertyChanged
{
protected List<ChildFoo> _Children = new List<ChildFoo>();
public foo()
{
}
public void AddChild(ChildFoo newChild)
{
DoAttachLogic(newChild);
_Children.Add(newChild);
NotifyPropertyChange("Children");
}
public void RemoveChild(ChildFoo oldChild)
{
DoRemoveLogic(oldChild);
_Children.Remove(oldChild);
NotifyPropertyChange("Children");
}
public ChildFoo[] Children
{
get
{
return _Children.ToArray();
}
}
}
Are there serious flaws with this design that I'm not seeing?
Every time the Children property is accessed we get the overhead of converting list to an array.
Any advice on this would be great.
This is what I do for normal code:
Public Readonly Property Childern As ObjectModel.ReadOnlyCollection(Of Child)
Get
Return New ObjectModel.ReadOnlyCollection(Of Child)(_ChildernList)
End Get
End Property
For WPF code I would just expose a subclass of ObservableCollection.
You should use ObservableCollection as field in your class, you then have full access to modify collection. Then expose this as ReadonlyObservableCollection via property.
And if you dont change collection itself (eg. nochildren = new ObservableCollection(), you should make field readonly), then you dont need any kind of notifyPropertyChanged on this property, because it doesnt change and collection itself handles those events for its children.
public class Child
{
public int Value { get; set; }
}
class MyClassWithReadonlyCollection
{
private readonly ObservableCollection<Child> _children = new ObservableCollection<Child>();
public MyClassWithReadonlyCollection()
{
_children.Add(new Child());
}
//No need to NotifyPropertyChange, because property doesnt change and collection handles this internaly
public ReadOnlyObservableCollection<Child> Children { get { return new ReadOnlyObservableCollection<Child>(_children); } }
}
I changed the "add child" and "remove child" to protected since you are saying you don't want other classes modifying your collection. I changed your List to ObservableCollection so you can recieve collection changed notifications. Since you are using an IList there is no need to call ToArray(), just access directly.
try this:
public class foo : INotifyPropertyChanged
{
protected ObservableCollection<ChildFoo> _Children = new ObservableCollection<ChildFoo>();
public foo() { }
protected void AddChild(ChildFoo oldChild)
{
DoAttachLogic(newChild);
_Children.Add(newChild);
NotifyPropertyChange("Children");
}
protected void RemoveChild(ChildFoo oldChild)
{
DoRemoveLogic(oldChild);
_Children.Remove(oldChild);
NotifyPropertyChange("Children");
}
public ChildFoo this[int n]
{
get
{
return _Children[n];
}
}
}
You could subclass BindingList and set AllowNew/AllowRemove to false. In your Child Add/Remove methods, you can set it to true, make the changes, then set it back to false. (Of course, you need to hide set access to AllowNew/AllowRemove from outside callers as well).
Another option - subclass Observable collection and override the InsertItem, RemoveItem, etc methods to behave as AddChild/RemoveChild would behave. Then callers can still access it in familiar ways, but not bypass your custom logic.
Subclassing an existing collection class is probably going to be easier (for you and the consumer) than wrapping a collection in another class.

how do I best create a set of list classes to match my business objects

I'm a bit fuzzy on the best way to solve the problem of needing a list for each of my business objects that implements some overridden functions.
Here's the setup:
I have a baseObject that sets up database, and has its proper Dispose() method
All my other business objects inherit from it, and if necessary, override Dispose()
Some of these classes also contain arrays (lists) of other objects. So I create a class that holds a List of these. I'm aware I could just use the generic List, but that doesn't let me add extra features like Dispose() so it will loop through and clean up.
So if I had objects called User, Project and Schedule, I would create UserList, ProjectList, ScheduleList.
In the past, I have simply had these inherit from List<> with the appropriate class named and then written the pile of common functions I wanted it to have, like Dispose().
this meant I would verify by hand, that each of these List classes had the same set of methods. Some of these classes had pretty simple versions of these methods that could have been inherited from a base list class.
I could write an interface, to force me to ensure that each of my List classes has the same functions, but interfaces don't let me write common base functions that SOME of the lists might override.
I had tried to write a baseObjectList that inherited from List, and then make my other Lists inherit from that, but there are issues with that (which is really why I came here). One of which was trying to use the Find() method with a predicate.
I've simplified the problem down to just a discussion of Dispose() method on the list that loops through and disposes its contents, but in reality, I have several other common functions that I want all my lists to have.
What's the best practice to solve this organizational matter?
--------edit---added an example class that I'm trying to clean up with a better approach --This next code block is from my AppVarList class, which inherits straight from List. Right now I've got a mixture of styles on these lists, because I'm trying to find the best way to manage all these and consolidate the code:
[Serializable]
public class AppVarList : List<AppVar>
{
private bool is_disposed = false;
private bool _NeedsSaving = false;
// Returns the AppVar, by name
public AppVar this[string index]
{
get { return this.Find(f => f.Key == index); }
set { this[this.FindIndex(f => f.Key == index)] = value; }
}
public AppVarList() { }
// instantiates the object and connects it to the DB
// and populates it
internal AppVarList(ref DBLib.DBAccess DA)
{
DataSet ds =
AppVar.SQLSelect(ref DA, 0, 0, false, "", "", "", "");
foreach (DataRow dr in ds.Tables[0].Rows)
{
this.Add(new AppVar(ref DA, dr));
}
// Destroy the dataset object
if (ds != null)-
you could certainly pull up some of your functionality into a base class:
[Serializable]
public class BaseDataList<T> : List<T>
where T : BaseObject // this is the key line, it ensure that
// T is a BaseObject so you can call
//BaseObject methods on T, should allow for you
//to put more implementation in this class than
// you could otherwise
{
private bool is_disposed = false;
private bool _NeedsSaving = false;
///this assumes that key is a property on BaseObject that everything implements
public T this[string index]
{
get { return this.Find(f => f.Key == index); }
set { this[this.FindIndex(f => f.Key == index)] = value; }
}
public BaseDataList() { }
// instantiates the object and connects it to the DB
// and populates it
internal BaseDataList(ref DBLib.DBAccess DA)
{
DataSet ds = GetDataSet();
foreach (DataRow dr in ds.Tables[0].Rows)
{
this.Add(new T(ref DA, dr));
}
// Destroy the dataset object
if (ds != null)//...
}
//abstract methods for extensibility...
protected abstract GetDataSet();
}
obviously this is just a rough sketch because i don't know all your requirements, but depending on how much implementation is shared in BaseObject you might be able to put a lot of functionality into BaseDataList (you should feel free to choose a better name). then all your other lists could just derive from BaseDataList.
For example if BaseObject implements IDisposable you could add this method to your class
protected void Dispose()
{
is_disposing = true;
foreach(T item in this)
{
item.Dispose();
}
}
then you would only have to write it once
You should make a common generic base class that inherits from System.Collections.ObjectModel.Collection<T>.
Your best bet is to add extension methods to your IEnumerable collection i.e.
public static ScheduleListExtentions
{
public static IEnumerable<ScheduleList> DoSomething(this IEnumerable<ScheduleList> mylist){
//Act on your collection in some mannor here
return mylist;
}
}

Class design: Access a List<T> directly or through methods?

For a newsroom system I have a class that contains a single news story. Inside this class is a private variable holding a generic List of image classes. The idea being a single story can contain multiple images.
The question is should I make the List variable public, so that I can add/remove images by addressing the List directly
public class News
{
private _images List<Images>();
public Images
{
get { return _images; }
set { _images = value }
}
}
or
Should I make the List variable private and then create methods to manipulate it:
public class News
{
private _images List<Images>();
public void AddImage( Image image )
public Image GetImage( int imageId )
public int GetImageCount()
public void DeleteImage( int imageId )
}
My spider sense is telling me to do the later, as it's abstracting things more. But on the flip side its creating more code.
By exposing the List, you expose an implementation detail. It will make it easier in the short run, but you'll have a hard time later if you decide to e.g. change the list to some other container (perhaps you need a Dictionary for lookup or something).
I would encapsulate it as it will make the type easier to maintain and enhance in the future.
I would explose a read-only view of the list as IList or IEnumerable, and methods for adding and removing elements. Like this:
public class News
{
private _images List<Images>();
public IList<Image> Images
{
get {return _images.AsReadOnly(); }
}
public void AddImage(Image image)
{
_images.Add(image);
// Do other stuff...
}
public void DeleteImage(Image image)
{
_images.Remove(image);
// Do other stuff...
}
}
If you expose the list as a property then it will be possible to do the following from outside the class:
News.Images = new List<Images>();
Is that what you want? (and you shouldn't because it breaks allsorts of encapsulation principles)
If not then use an ICollection<T> interface:
class News
{
public ICollection<Image> Images
{
get;
private set;
}
}
or
class News
{
private List<Image> images = new List<Image>();
public ICollection<Image> Images
{
get
{
// You can return an ICollection interface directly from a List
return images;
}
}
}
ICollection<T> has methods such as Add, Remove, Clear, Count.
If you want a read-only container return a ReadOnlyCollection
class News
{
private List<Image> images = new List<Image>();
public ReadOnlyCollection<Image> Images
{
get
{
// This wraps the list in a ReadOnlyCollection object so it doesn't actually copy the contents of the list just a reference to it
return images.AsReadOnly();
}
}
}
It depends on whether you need/(would need) to control adding/getting and deleting images or possibility to change container.
Davy Brion made a post on this last week. He favors exposing an IEnumerable<> property and providing an add & remove method for manipulation.
Most of the time you only want to loop through the collection, so IEnumerable<> will do the trick. Besides, you can switch the actual implementation (List, Set, ...) when needed without any hassle, when switching to another ORM this could prove very valuable.
http://davybrion.com/blog/2009/10/stop-exposing-collections-already/
Expose a read only implementation of the list and expose methods for manipulating the list. I would do it like this:
public class News
{
private IList<Image> _images;
public void News()
{
_images = new List<Image>();
}
public void AddImage(Image image) { ... }
public void RemoveImage(Image image) { ... }
public IEnumberable<Image> Images
{
get { return _images; }
}
}
Note that the Images property can be cast as List but you can return it in a ReadyOnlyCollection wrapper if needed. Count() and ElementAt() extension methods replace your GetImageCount and GetImage methods.
For accessing the elements you could consider using a ReadOnlyCollection or IEnumerable type. However in order to keep encapsulation ensured, you should use insert/remove methods, this way you don't need the set of the property anymore.
Edit: Someone beat me to it during typing this answer ;)
If you expose the List directly, you would have to rely on it's mechanics for all Image-related actions (Add, Delete, Count, ...)
I would still expose a collection of Images (ReadOnlyCollection is usually fine) to make the accessing operations of the list easier for both the developer and the consumer, but all create/update/delete logic should be wrapped inside your class.
I think this is a design consideration that only you can decide. Your second approach is hiding an implementation detail that is you used a List to store images. On the other side, the first solution gives you one advantage. You can use all the List methods including those extensions that are always useful. Using the second solution, you can also implement a ToList() method that would return a new constructed List. Changes to this List wouldn't affect the internal structure of your class. The down side is, if the internal Image List is too big, it could affect performance, as it would always build a new List on ToList() but I wouldn't expect this method be called many times.
Another solution would be to expose a ReadOnlyCollection.
I would just expose the list as an IList:
public class News
{
private List<Image> _images;
public IList<Image> Images
{
get { return _images; }
set { _images = value; }
}
}
If you later want to change the implementation, you can do this without breaking the contract:
public class News
{
public News(SomeCollection<Image> images)
{
_images = images;
Images = new ListView(this);
}
private SomeCollection<Image> _images;
public IList<Image> Images { get; private set; }
private class News.ListView : IList<Image>
{
public ListView(News news)
{
_news = news;
}
private News _news;
// Implement the methods to manipulate _news._images
}
}

Categories