Cả C ++ và C # đều thiếu những cách dễ dàng để tạo ra một loại mới giống hệt về mặt ngữ nghĩa với một loại hiện tại. Tôi thấy những 'typedefs' như vậy hoàn toàn cần thiết cho lập trình an toàn kiểu và thật xấu hổ c # không có chúng tích hợp sẵn. Sự khác biệt giữa void f(string connectionID, string username)
để void f(ConID connectionID, UserName username)
là rõ ràng ...
(Bạn có thể đạt được thứ gì đó tương tự trong C ++ với boost trong BOOST_STRONG_TYPEDEF)
Nó có thể hấp dẫn để sử dụng thừa kế nhưng điều đó có một số hạn chế lớn:
- nó sẽ không hoạt động cho các loại nguyên thủy
- loại dẫn xuất vẫn có thể được chuyển sang loại ban đầu, tức là chúng ta có thể gửi nó đến một hàm nhận loại ban đầu của chúng ta, điều này đánh bại toàn bộ mục đích
- chúng ta không thể xuất phát từ các lớp niêm phong (và tức là nhiều lớp .NET được niêm phong)
Cách duy nhất để đạt được điều tương tự trong C # là kết hợp kiểu của chúng tôi trong một lớp mới:
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();
}
Trong khi điều này sẽ làm việc, nó rất dài dòng cho một typedef. Ngoài ra, chúng tôi có một vấn đề với việc tuần tự hóa (tức là với Json) vì chúng tôi muốn tuần tự hóa lớp thông qua thuộc tính Hợp thành của nó.
Dưới đây là lớp trình trợ giúp sử dụng "Mẫu mẫu định kỳ tò mò" để làm cho việc này đơn giản hơn nhiều:
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);
}
}
}
Với Trình soạn thảo, lớp trên trở nên đơn giản:
sealed Class SomeTypeTypeDef : Composer<SomeTypeTypeDef, SomeType> {
public SomeTypeTypeDef(SomeType composed) : base(composed) {}
// proxy the methods we want
public void Method() => Composed.Method();
}
Và ngoài ra, SomeTypeTypeDef
nó sẽ tuần tự hóa thành Json theo cách tương tự SomeType
.
Hi vọng điêu nay co ich !