c# - How to Ensure Immutability of a Generic -
this example in c# question applies oo language. i'd create generic, immutable class implements ireadonlylist. additionally, class should have underlying generic ilist unable modified. initially, class written follows:
public class datum<t> : ireadonlylist<t> { private ilist<t> objects; public int count { get; private set; } public t this[int i] { { return objects[i]; } private set { this.objects[i] = value; } } public datum(ilist<t> obj) { this.objects = obj; this.count = obj.count; } ienumerator ienumerable.getenumerator() { return this.getenumerator(); } public ienumerator<t> getenumerator() { return this.objects.getenumerator(); } }
however, isn't immutable. can tell, changing initial ilist 'obj' changes datum's 'objects'.
static void main(string[] args) { list<object> list = new list<object>(); list.add("one"); datum<object> datum = new datum<object>(list); list[0] = "two"; console.writeline(datum[0]); }
this writes "two" console. point of datum immutability, that's not okay. in order resolve this, i've rewritten constructor of datum:
public datum(ilist<t> obj) { this.objects = new list<t>(); foreach(t t in obj) { this.objects.add(t); } this.count = obj.count; }
given same test before, "one" appears on console. great. but, if datum contains collection of non-immutable collection , 1 of non-immutable collections modified?
static void main(string[] args) { list<object> list = new list<object>(); list<list<object>> containinglist = new list<list<object>>(); list.add("one"); containinglist.add(list); datum<list<object>> d = new datum<list<object>>(containinglist); list[0] = "two"; console.writeline(d[0][0]); }
and, expected, "two" printed out on console. so, question is, how make class immutable?
you can't. or rather, don't want to, because ways of doing bad. here few:
1. struct
-only
add where t : struct
datum<t>
class. struct
s usually immutable, if contains mutable class
instances, can still modified (thanks servy). major downside classes out, immutable ones string
, immutable class make.
var e = new extraevilstruct(); e.mutable = new mutable { myval = 1 }; datum<extraevilstruct> datum = new datum<extraevilstruct>(new[] { e }); e.mutable.myval = 2; console.writeline(datum[0].mutable.myval); // 2
2. create interface
create marker interface , implement on immutable types create. major downside built-in types out. , don't know if classes implementing truly immutable.
public interface iimmutable { // space intentionally left blank, except comment } public class datum<t> : ireadonlylist<t> t : iimmutable
3. serialize!
if serialize , deserialize objects passed (e.g. json.net), can create completely-separate copies of them. upside: works many built-in , custom types might want put here. downside: requires time , memory create read-only list, , requires objects serializable without losing important. expect links objects outside of list destroyed.
public datum(ilist<t> obj) { this.objects = jsonconvert.deserializeobject<ilist<t>>(jsonconvert.serializeobject(obj)); this.count = obj.count; }
i suggest document datum<t>
class should used store immutable types. sort of unenforced implicit requirement exists in other types (e.g. dictionary
expects tkey
implements gethashcode
, equals
in expected way, including immutability), because it's difficult not way.
Comments
Post a Comment