Reputation: 189
I'm new in WPF, following mvvm pattern.
I have defined two class, int class abc, i don't want to change _xyz so i defined readonly, it can be set only once through constructor of abc
class xyz
{
private int _x;
public int X
{
get { return _x ;}
public xyz(int xvalue) { this.X = xvalue; }
}
class abc
{
public abc(List<xyz> listXyz)
{
_xyz = new List<xyz>(listXyz);
}
private readonly List<xyz> _xyz;
public List<xyz> XYZ
{
get
{
return _xyz;
}
}
}
but if i implement it by below way,
which manipulates any elements inside, since i have exposed it as interface
var model = new abc(....);
model.XYZ.Add(new xyz()); model.XYZ.Clear();
now my question is how to restrict XYZ to manipulate in below way? I don't want to change it by below way, it should be assign only once by constructor of abc.
Upvotes: 2
Views: 190
Reputation: 133
Hi you could consider extending IList, this will allow you to make a read-only list which should solve all of the problems associated with other methods. Here is the code I just wrote that implements what I am talking about. Note: When the list is read-only it will throw a custom exception; you could remove this if you wanted.
public class CustomList<T> : IList<T>
{
private IList<T> _list;
private Boolean _isReadOnly;
public CustomList(IList<T> source, Boolean isReadOnly)
{
_list = source;
_isReadOnly = isReadOnly;
}
public int IndexOf(T item)
{
return _list.IndexOf(item);
}
public void Insert(int index, T item)
{
if (_isReadOnly == true)
{
throw new Exception("List is readonly. Method = Insert(int index, T item)");
}
_list.Insert(index, item);
}
public void RemoveAt(int index)
{
if (_isReadOnly == true)
{
throw new Exception("List is readonly. Method = RemoveAt(int index)");
}
_list.RemoveAt(index);
}
public T this[int index]
{
get
{
return _list[index];
}
set
{
if (_isReadOnly == true)
{
throw new Exception("List is readonly. Property = this[int index]");
}
_list[index] = value;
}
}
public void Add(T item)
{
if (_isReadOnly == true)
{
throw new Exception("List is readonly. Method = Add(T item)");
}
_list.Add(item);
}
public void Clear()
{
if (_isReadOnly == true)
{
throw new Exception("List is readonly. Method = Clear()");
}
_list.Clear();
}
public bool Contains(T item)
{
return _list.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_list.CopyTo(array, arrayIndex);
}
public int Count
{
get { return _list.Count; }
}
public bool IsReadOnly
{
get { return _isReadOnly; }
}
public bool Remove(T item)
{
if (_isReadOnly == true)
{
throw new Exception("List is readonly. Method = Remove(T item)");
}
return _list.Remove(item);
}
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _list.GetEnumerator();
}
}
Upvotes: 1
Reputation: 18578
If you expose your collection as List then it is not possible to restrict it. Instead expose your collection as IEnumerable
public IEnumerable<xyz> XYZ
{
get
{
return _xyz.AsEnumerable();;
}
}
Upvotes: 0
Reputation: 3603
You can't modify the behavior of list (so yes while you can prevent assignments of the list itself, you can't prevent someone from using it's methods).
What you CAN do is not expose the list at all by simply providing an IEnumerable.
The naive approach would be
private readonly IEnumerable<xyz> _xyz;
public List<xyz> XYZ
{
get
{
return _xyz;
}
}
However this will not work as the caller can simply cast it back as such
((List<xyz>)myabc).Add(whatever)
What you can do is not return the list at all, but use the yield keyword to have the data streamed (foreach compatible) without ever returning the backing class:
private readonly IEnumerable<xyz> _xyz;
public IEnumerable<xyz> XYZ
{
get
{
foreach(var item in _xyz)
{
yield return item; // Every time will get returned 1 by 1 as the caller énumérâtes this, no list is ever returned
}
}
}
Upvotes: 1