Kendimi pek çok değişmez sınıf oluşturmak zorundayım ve gereksiz bilgi olmadan bunu yapmanın bir yolunu bulmak istiyorum. Anonim bir yazı kullanamıyorum çünkü bu sınıfları yöntemlerden döndürmem gerekiyor. Ben intellisense desteği istiyorum, bu yüzden Sözlükler, dinamik ya da bunun gibi bir şey kullanmamayı tercih ederim. Ayrıca, Tuple <> 'u dışlayan iyi adlandırılmış özellikler istiyorum. Şimdiye kadar, bazı desenler denedim:C# içinde değişmez bir sınıf oluşturmanın en kısa yolu nedir?
// inherit Tuple<>. This has the added benefit of giving you Equals() and GetHashCode()
public class MyImmutable : Tuple<int, string, bool> {
public MyImmutable(int field1, string field2, bool field3) : base(field1, field2, field3) { }
public int Field1 { get { return this.Item1; } }
public string Field2 { get { return this.Item2; } }
public bool Field3 { get { return this.Item3; } }
}
///////////////////////////////////////////////////////////////////////////////////
// using a custom SetOnce<T> struct that throws an error if set twice or if read before being set
// the nice thing about this approach is that you can skip writing a constructor and
// use object initializer syntax.
public class MyImmutable {
private SetOnce<int> _field1;
private SetOnce<string> _field2;
private SetOnce<bool> _field3;
public int Field1 { get { return this._field1.Value; } set { this._field1.Value = value; }
public string Field2 { get { return this._field2.Value; } set { this._field2.Value = value; }
public bool Field3 { get { return this._field3.Value; } set { this._field3.Value = value; }
}
///////////////////////////////////////////////////////////////////////////////////
// EDIT: another idea I thought of: create an Immutable<T> type which allows you to
// easily expose types with simple get/set properties as immutable
public class Immutable<T> {
private readonly Dictionary<PropertyInfo, object> _values;
public Immutable(T obj) {
// if we are worried about the performance of this reflection, we could always statically cache
// the getters as compiled delegates
this._values = typeof(T).GetProperties()
.Where(pi => pi.CanRead)
// Utils.MemberComparer is a static IEqualityComparer that correctly compares
// members so that ReflectedType is ignored
.ToDictionary(pi => pi, pi => pi.GetValue(obj, null), Utils.MemberComparer);
}
public TProperty Get<TProperty>(Expression<Func<T, TProperty>> propertyAccessor) {
var prop = (PropertyInfo)((MemberExpression)propertyAccessor.Body).Member;
return (TProperty)this._values[prop];
}
}
// usage
public class Mutable { int A { get; set; } }
// we could easily write a ToImmutable extension that would give us type inference
var immutable = new Immutable<Mutable>(new Mutable { A = 5 });
var a = immutable.Get(m => m.A);
// obviously, this is less performant than the other suggestions and somewhat clumsier to use.
// However, it does make declaring the immutable type quite concise, and has the advantage that we can make
// any mutable type immutable
///////////////////////////////////////////////////////////////////////////////////
// EDIT: Phil Patterson and others mentioned the following pattern
// this seems to be roughly the same # characters as with Tuple<>, but results in many
// more lines and doesn't give you free Equals() and GetHashCode()
public class MyImmutable
{
public MyImmutable(int field1, string field2, bool field3)
{
Field1 = field1;
Field2 = field2;
Field3 = field3;
}
public int Field1 { get; private set; }
public string Field2 { get; private set; }
public bool Field3 { get; private set; }
}
Bunlar, salt okunur alanları yaratan yapıcı aracılığıyla onları ayarlamak ve özellikleri aracılığıyla onları teşhir "standart" desen daha hem biraz daha az ayrıntılıdır. Bununla birlikte, her iki yöntemde hala çok miktarda boilerplate var.
Herhangi bir fikrin var mı?
İkinci formunuz değişmez değil - 'Field1' öğesini getirip ardından ayarlayarak ve sonra yeniden getirerek bir değişiklik gözlemleyebilirsiniz. ('SetOnce', tanımlanmamış bir kümeden önce getirmeyi engellemezse.) –
@JonSkeet SetOnce, ayarlanmadan önce getirmeyi engeller (ben gönderiyi gönderirim). – ChaseMedallion
Ne yazık ki, ortaya çıkardığınız problemin slam-dunk çözümü yoktur. Dil tasarım ekibi bunun farkında. Umarım bu bir gün ele alınacaktır. –