What are the drawbacks of this pattern to enforce immutability? - c#

Given the following class:
public static class ComboModel
{
public static Dictionary<int, int[]> Items()
{
return new Dictionary<int, int[]>
{
{
1,
new[] {
2,
3,
4
}
}
};
}
}
I want to ensure immutability of the data in the class, but this feels javascript-y and has drawn some vague (but strong) criticism from my peers. What is wrong with it?

Just use ReadOnlyDictionary, and allocate it only once:
public static class ComboModel {
private static readonly ReadOnlyDictionary<int, int[]> _items = new ReadOnlyDictionary<int, int[]>(new Dictionary<int, int[]> {
{
1,
new[] {
2,
3,
4
}
}
});
public static IReadOnlyDictionary<int, int[]> Items
{
get { return _items; }
}
}
Note that not only you allocate new instance on each call, as others already mentioned - you also provide wrong feeling to the caller that he can modify that dictionary. In ReadOnlyDictionary there are no methods that can modify it.
There are other benefits when caller knows structure it received cannot be changed: for example he can safely process items there with multiple threads.
Update: of course readonly collections do not magically make objects stored in that collections readonly - just the collection itself. If you want to ensure immutability of int[] arrays in your example, just make them readonly too:
public static class ComboModel {
private static readonly IReadOnlyDictionary<int, ReadOnlyCollection<int>> _items = new ReadOnlyDictionary<int, ReadOnlyCollection<int>>(new Dictionary<int, ReadOnlyCollection<int>> {
{
1,
Array.AsReadOnly(new[] {
2,
3,
4
})
}
});
public static IReadOnlyDictionary<int, ReadOnlyCollection<int>> Items
{
get { return _items; }
}
}

Related

C# Assign static dictionary to filtered version of other dictionary in static class

I have a class, with some global and constant dictionaries. Like:
public static class Constants
{
public static Dictionary<string, MyObject> MyDictionary= new Dictionary<string, MyObject>()
{
{"first", new MyObject()},
{"second", new MyObject()},
};
}
Lets say I would like another dictionary, to be like that only with some added and removed elements. Is there a way to achieve that, within the static class? I imagine something like:
public static Dictionary<string, MyObject> MyOtherDictionary = MyDictionary.Remove("second").Add("Third", new MyObject())
But I know that does not work, so is there any way I can achieve this?
No, that doesnt work in this way for two reasons:
Remove returns a bool, you can't use Add on a bool
even if you make it compile, you don't want to modify the other dictionary but you want to create a new dictionary which contains similar items, you can use the constructor:
public static Dictionary<string, MyObject> MyOtherDictionary;
// ...
static Constants
{
MyOtherDictionary = new Dictionary<string, MyObject>(MyDictionary);
MyOtherDictionary.Remove("second");
MyOtherDictionary.Add("Third", new MyObject());
}
You could do it using properties instead
public static class Constants
{
public static Dictionary<string, MyObject> myDictionary
{
get
{
return new Dictionary<string, MyObject>()
{
{ "first", new MyObject()},
{ "second", new MyObject()},
};
}
}
static Dictionary<string, MyObject> _myOtherDictionary;
public static Dictionary<string, MyObject> myOtherDictionary
{
get
{
_myOtherDictionary = myDictionary;
_myOtherDictionary.Remove("first");
_myOtherDictionary.Add("third", new MyObject());
return _myOtherDictionary;
}
}
}

C# prevent dictionary property elements from being set outside class?

Title says it all. Reducing access through access modifiers only prevents reinitialising the property; It doesn't prevent elements from becoming global state (bad practice). I know there's a workaround with List<T>'s but what should I do for any other indexed collection?
public class Start
{
public static void main()
{
//CODE SMELL AHEAD
AttendanceManager.MuteStatuses[0] = new KeyValuePair <string, string> ("", "");
}
}
public static class AttendanceManager
{
public static HybridDictionary MuteStatuses
{
get
{
playersMuteStatuses.Add ("", "");
return playersMuteStatus;
}
}
private static HybridDictionary playersMuteStatus = new HybridDictionary();
}
Dont use HybridDictionary. We do have IReadOnlyDictionary<T>
private Dictionary<string, string> playersMuteStatus = new... ;
public IReadOnlyDictionary<string, string> MuteStatuses
{
get
{
return playersMuteStatus as IReadOnlyDictionary<string, string>;
}
}
Write helper methods:
public static void AddMuteStatus()
=> playersMuteStatus.Add("", "");
public static object GetMuteStatus(object idx)
=> return playersMuteStatus[idx];

Setting a Private Dictionary [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have a working example of a Dictionary<string, int>. I have a requirement to set the Dictionary to a private Dictionary and check the value.
Currently I have:
protected void btnSubmit_Click(object sender, EventArgs e)
{
Dictionary<string, int> docTypeValue = new Dictionary<string, int>();
docTypeValue.Add("OSD", 1);
docTypeValue.Add("POD", 2);
docTypeValue.Add("REC", 3);
docTypeValue.Add("CLAINF", 4);
docTypeValue.Add("RATE", 5);
docTypeValue.Add("OTHER", 6);
docTypeValue.Add("CARINV", 7);
docTypeValue.Add("PODDET", 8);
docTypeValue.Add("BOLPO", 9);
litText.Text = docTypeValue[txtDocType.Text].ToString();
}
This works as expected. Would I need to make use of a property? ie below
private Dictionary<string, int> DocTypeValue
{
get;
set;
}
How can I refactor what I have above to create the suggested private Dictionary?
You're looking for something like this. Make use of the Collection Initializer feature.
private Dictionary<string, int> docTypeValue = new Dictionary<string, int>
{
{ "OSD", 1 },
{"POD", 2},
{"REC", 3},
{"CLAINF", 4},
//...
};
If you don't want non-members to be able to modify the contents of the dictionary, but want to make it available it is possible to do something like this:
private Dictionary<String, Int32> dictionary = ...
public IEnumerable<Int32> Dictionary { get{ return dictionary.Values; } }
// Other methods in the class can still access the 'dictionary' (lowercase).
// But external users can only see 'Dictionary' (uppercase).
void AddItemToDictoinary(String key, Int32 value) {
dictionary.Add(key, value); // dictionary is accessible within the class.
}
or using an indexer like this:
private Dictionary<String, Int32> dictionary = ...
public Int32 this[String key] { get { return dictionary[key]; } }
// Same as above - within the class you can still add items to the dictionary.
void AddItemToDictoinary(String key, Int32 value) {
dictionary.Add(key, value);
}
using the indexer takes advantage of the BST behind Dictionary<T, U> (rather than using sequential search). So if you're dictionary is defined like so:
class SneakyDictionary {
private Dictionary<String, Int32> dictionary = ...
public Int32 this[String key] { get { return dictionary[key]; } }
// Same as above - within the class you can still add items to the dictionary.
void AddItemToDictoinary(String key, Int32 value) {
dictionary.Add(key, value);
}
}
You would use it like this:
public static void Main() {
SneakyDictionary dictionary = ...
dictionary.AddItemToDictionary("one", 1);
dictionary.AddItemToDictionary("two", 2);
dictionary.AddItemToDictionary("three", 3);
// Access items in dictionary using indexer:
Console.WriteLine(dictionary["one"]);
}
It's a matter of range. If your dictionary is useful for the whole class you could instantiate it a as private static (or not) readonly field with initializer :
private static readonly Dictionary<string, int> docTypeValue = new Dictionary<string, int>
{
{ "OSD", 1 },
{"POD", 2},
{"REC", 3},
{"CLAINF", 4},
// and so on
};
But you could also rely on a .Net feature which is called static constructor :
private static Dictionary<string, int> docTypeValue;
static YOURCLASSNAME()
{
docTypeValue = new Dictionary<string, int>();
docTypeValue.Add("OSD", 1);
// and so on
}
Or a combination of these.
In both cases your dictionary will be initialized once, against your current approach.
If it's a private member you don't need a property, just use -
private Dictionary<string, int> _docTypeValue;
As per my understanding about your requirement " I have a requirement to set the Dictionary to a private Dictionary and check the value." you need to have this dictionary on the class level you do not need to create property for the dictionary just create it as a private dictionary.
similar as in the above answer.

How should I use properties when dealing with read-only List<T> members

When I want to make a value type read-only outside of my class I do this:
public class myClassInt
{
private int m_i;
public int i {
get { return m_i; }
}
public myClassInt(int i)
{
m_i = i;
}
}
What can I do to make a List<T> type readonly (so they can't add/remove elements to/from it) outside of my class? Now I just declare it public:
public class myClassList
{
public List<int> li;
public myClassList()
{
li = new List<int>();
li.Add(1);
li.Add(2);
li.Add(3);
}
}
You can expose it AsReadOnly. That is, return a read-only IList<T> wrapper. For example ...
public ReadOnlyCollection<int> List
{
get { return _lst.AsReadOnly(); }
}
Just returning an IEnumerable<T> is not sufficient. For example ...
void Main()
{
var el = new ExposeList();
var lst = el.ListEnumerator;
var oops = (IList<int>)lst;
oops.Add( 4 ); // mutates list
var rol = el.ReadOnly;
var oops2 = (IList<int>)rol;
oops2.Add( 5 ); // raises exception
}
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst; }
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
Steve's answer also has a clever way to avoid the cast.
There is limited value in attempting to hide information to such an extent. The type of the property should tell users what they're allowed to do with it. If a user decides they want to abuse your API, they will find a way. Blocking them from casting doesn't stop them:
public static class Circumventions
{
public static IList<T> AsWritable<T>(this IEnumerable<T> source)
{
return source.GetType()
.GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
.Select(f => f.GetValue(source))
.OfType<IList<T>>()
.First();
}
}
With that one method, we can circumvent the three answers given on this question so far:
List<int> a = new List<int> {1, 2, 3, 4, 5};
IList<int> b = a.AsReadOnly(); // block modification...
IList<int> c = b.AsWritable(); // ... but unblock it again
c.Add(6);
Debug.Assert(a.Count == 6); // we've modified the original
IEnumerable<int> d = a.Select(x => x); // okay, try this...
IList<int> e = d.AsWritable(); // no, can still get round it
e.Add(7);
Debug.Assert(a.Count == 7); // modified original again
Also:
public static class AlexeyR
{
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
}
IEnumerable<int> f = a.AsReallyReadOnly(); // really?
IList<int> g = f.AsWritable(); // apparently not!
g.Add(8);
Debug.Assert(a.Count == 8); // modified original again
To reiterate... this kind of "arms race" can go on for as long as you like!
The only way to stop this is to completely break the link with the source list, which means you have to make a complete copy of the original list. This is what the BCL does when it returns arrays. The downside of this is that you are imposing a potentially large cost on 99.9% of your users every time they want readonly access to some data, because you are worried about the hackery of 00.1% of users.
Or you could just refuse to support uses of your API that circumvent the static type system.
If you want a property to return a read-only list with random access, return something that implements:
public interface IReadOnlyList<T> : IEnumerable<T>
{
int Count { get; }
T this[int index] { get; }
}
If (as is much more common) it only needs to be enumerable sequentially, just return IEnumerable:
public class MyClassList
{
private List<int> li = new List<int> { 1, 2, 3 };
public IEnumerable<int> MyList
{
get { return li; }
}
}
UPDATE Since I wrote this answer, C# 4.0 came out, so the above IReadOnlyList interface can take advantage of covariance:
public interface IReadOnlyList<out T>
And now .NET 4.5 has arrived and it has... guess what...
IReadOnlyList interface
So if you want to create a self-documenting API with a property that holds a read-only list, the answer is in the framework.
JP's answer regarding returning IEnumerable<int> is correct (you can down-cast to a list), but here is a technique that prevents the down-cast.
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.Select(x => x); } // Identity transformation.
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
The identity transformation during enumeration effectively creates a compiler-generated iterator - a new type which is not related to _lst in any way.
Eric Lippert has a series of articles on Immutability In C# on his blog.
The first article in the series can be found here.
You might also find useful Jon Skeet's answer to a similar question.
public List<int> li;
Don't declare public fields, it's generally considered bad practice... wrap it in a property instead.
You can expose your collection as a ReadOnlyCollection :
private List<int> li;
public ReadOnlyCollection<int> List
{
get { return li.AsReadOnly(); }
}
public class MyClassList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.AsReadOnly(); }
}
}
To check it
MyClassList myClassList = new MyClassList();
var lst= (IList<int>)myClassList.ListEnumerator ;
lst.Add(4); //At this point ypu will get exception Collection is read-only.
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
if I add to Earwicker's example
...
IEnumerable<int> f = a.AsReallyReadOnly();
IList<int> g = f.AsWritable(); // finally can't get around it
g.Add(8);
Debug.Assert(a.Count == 78);
I get InvalidOperationException: Sequence contains no matching element.

const Dictionary in c#

I have a class in C# that contains a Dictionary, which I want to create and ensure nothing as added, edited or removed from this dictionary as long as the class which contains it exists.
readonly doesn't really help, once I tested and saw that I can add items after. Just for instance, I created an example:
public class DictContainer
{
private readonly Dictionary<int, int> myDictionary;
public DictContainer()
{
myDictionary = GetDictionary();
}
private Dictionary<int, int> GetDictionary()
{
Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(1, 2);
myDictionary.Add(2, 4);
myDictionary.Add(3, 6);
return myDictionary;
}
public void Add(int key, int value)
{
myDictionary.Add(key, value);
}
}
I want the Add method not to work. If possible, I want it not to even compile. Any suggestions?
Actually, I'm worried for it is code that will be open for a lot of people to change. So, even if I hide the Add method, it will be possible for someone to "innocently" create a method which add a key, or remove another. I want people to look and know they shouldn't change the dictionary in any ways. Just like I have with a const variable.
Hide the Dictionary totally. Just provide a get method on the DictContainer class that retrieves items from the dictionary.
public class DictContainer
{
private readonly Dictionary<int, int> myDictionary;
public DictContainer()
{
myDictionary = GetDictionary();
}
private Dictionary<int, int> GetDictionary()
{
Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(1, 2);
myDictionary.Add(2, 4);
myDictionary.Add(3, 6);
return myDictionary;
}
public this[int key]
{
return myDictionary[key];
}
}
Don't define the Add Method.
Keep the myDictionary variable private and expose a Getter/Indexer so that it can only be read from outside that class..
There's no built-in way to do that, consider using a wrapper class.
interface IReadOnlyDic<Key, Value>
{
void Add(Key key, Value value);
}
class ReadOnlyDic<Key, Value> : Dictionary<Key, Value>, IReadOnlyDic<Key, Value>
{
public new void Add(Key key, Value value)
{
//throw an exception or do nothing
}
#region IReadOnlyDic<Key,Value> Members
void IReadOnlyDic<Key, Value>.Add(Key key, Value value)
{
base.Add(key, value);
}
#endregion
}
to add custom items;
IReadOnlyDic<int, int> dict = myDictInstance as IReadOnlyDic<int, int>;
if (dict != null)
dict.Add(1, 155);
and this is another way
class ReadOnlyDic<Key, Value> : Dictionary<Key, Value>
{
private bool _locked = false;
public new void Add(Key key, Value value)
{
if (!_locked)
{
base.Add(key, value);
}
else
{
throw new ReadOnlyException();
}
}
public void Lock()
{
_locked = true;
}
}
FYI, now it is built-in to .net 4.5.
http://msdn.microsoft.com/en-us/library/gg712875(v=vs.110).aspx
Similar to Neil's answer:
Hide the Dictionary totally. Just provide a get method on the DictContainer class that retrieves items from the dictionary. If you want to use [] override you need getter settter method (atleast any one get/set)
public class DictContainer
{
private readonly Dictionary<int, int> myDictionary;
public DictContainer()
{
myDictionary = GetDictionary();
}
private Dictionary<int, int> GetDictionary()
{
Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(1, 2);
myDictionary.Add(2, 4);
myDictionary.Add(3, 6);
return myDictionary;
}
public this[int key]
{
get => myDictionary[key];
}
}

Categories

Resources