Hem C ++ hem de C # mevcut bir türle semantik olarak aynı olan yeni bir tür oluşturmanın kolay yollarını kaçırmaktadır . Bu tür 'typedefs' türünü güvenli programlama için tamamen gerekli buluyorum ve gerçek bir utanç c # yerleşik değildir. Arasındaki fark void f(string connectionID, string username)
içinvoid f(ConID connectionID, UserName username)
açıktır ...
(C ++ 'da benzer bir şeyi BOOST_STRONG_TYPEDEF'te artırarak elde edebilirsiniz)
Kalıtım kullanmak cazip gelebilir, ancak bazı büyük sınırlamaları vardır:
- ilkel tipler için çalışmaz
- türetilmiş tip hala orijinal türe dökülebilir, yani orijinal tipimizi alan bir fonksiyona gönderebiliriz, bu tüm amacı yener
- kapalı sınıflardan türeyemeyiz (ve birçok .NET sınıfı kapalıdır)
C # 'da benzer bir şeyi elde etmenin tek yolu, türümüzü yeni bir sınıfta oluşturmaktır:
Class SomeType {
public void Method() { .. }
}
sealed Class SomeTypeTypeDef {
public SomeTypeTypeDef(SomeType composed) { this.Composed = composed; }
private SomeType Composed { get; }
public override string ToString() => Composed.ToString();
public override int GetHashCode() => HashCode.Combine(Composed);
public override bool Equals(object obj) => obj is TDerived o && Composed.Equals(o.Composed);
public bool Equals(SomeTypeTypeDefo) => object.Equals(this, o);
// proxy the methods we want
public void Method() => Composed.Method();
}
Bu işe yarayacak olsa da, sadece bir typedef için çok ayrıntılı. Ayrıca, sınıfın Composed özelliği aracılığıyla serileştirmek istediğimiz için serileştirme (yani Json'a) ile ilgili bir sorunumuz var.
Aşağıda bunu daha basit hale getirmek için "Merakla Yinelenen Şablon Kalıbı" kullanan bir yardımcı sınıf bulunmaktadır:
namespace Typedef {
[JsonConverter(typeof(JsonCompositionConverter))]
public abstract class Composer<TDerived, T> : IEquatable<TDerived> where TDerived : Composer<TDerived, T> {
protected Composer(T composed) { this.Composed = composed; }
protected Composer(TDerived d) { this.Composed = d.Composed; }
protected T Composed { get; }
public override string ToString() => Composed.ToString();
public override int GetHashCode() => HashCode.Combine(Composed);
public override bool Equals(object obj) => obj is Composer<TDerived, T> o && Composed.Equals(o.Composed);
public bool Equals(TDerived o) => object.Equals(this, o);
}
class JsonCompositionConverter : JsonConverter {
static FieldInfo GetCompositorField(Type t) {
var fields = t.BaseType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy);
if (fields.Length!=1) throw new JsonSerializationException();
return fields[0];
}
public override bool CanConvert(Type t) {
var fields = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy);
return fields.Length == 1;
}
// assumes Compositor<T> has either a constructor accepting T or an empty constructor
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
while (reader.TokenType == JsonToken.Comment && reader.Read()) { };
if (reader.TokenType == JsonToken.Null) return null;
var compositorField = GetCompositorField(objectType);
var compositorType = compositorField.FieldType;
var compositorValue = serializer.Deserialize(reader, compositorType);
var ctorT = objectType.GetConstructor(new Type[] { compositorType });
if (!(ctorT is null)) return Activator.CreateInstance(objectType, compositorValue);
var ctorEmpty = objectType.GetConstructor(new Type[] { });
if (ctorEmpty is null) throw new JsonSerializationException();
var res = Activator.CreateInstance(objectType);
compositorField.SetValue(res, compositorValue);
return res;
}
public override void WriteJson(JsonWriter writer, object o, JsonSerializer serializer) {
var compositorField = GetCompositorField(o.GetType());
var value = compositorField.GetValue(o);
serializer.Serialize(writer, value);
}
}
}
Composer ile yukarıdaki sınıf basitçe:
sealed Class SomeTypeTypeDef : Composer<SomeTypeTypeDef, SomeType> {
public SomeTypeTypeDef(SomeType composed) : base(composed) {}
// proxy the methods we want
public void Method() => Composed.Method();
}
Buna ek olarak, SomeTypeTypeDef
irade aynı şekilde Json'aSomeType
.
Bu yardımcı olur umarım !