ทั้ง C ++ และ C # ขาดวิธีง่ายๆในการสร้างรูปแบบใหม่ซึ่งมีความหมายเหมือนกันกับประเภทที่มีอยู่ ฉันพบว่า 'typedefs' มีความสำคัญอย่างยิ่งต่อการเขียนโปรแกรมแบบปลอดภัยและความอัปยศที่แท้จริง c # ไม่ได้มีในตัว ความแตกต่างระหว่างvoid f(string connectionID, string username)
ถึงvoid f(ConID connectionID, UserName username)
ชัดเจน ...
(คุณสามารถบรรลุสิ่งที่คล้ายกันใน C ++ พร้อมกับเพิ่ม BOOST_STRONG_TYPEDEF)
อาจเป็นการดึงดูดให้ใช้มรดก แต่มีข้อ จำกัด ที่สำคัญบางประการ:
- มันจะไม่ทำงานสำหรับประเภทดั้งเดิม
- ประเภทที่ได้รับยังคงสามารถนำไปใช้กับประเภทดั้งเดิมได้เช่นเราสามารถส่งไปยังฟังก์ชันที่รับประเภทดั้งเดิมของเราได้
- เราไม่สามารถสืบทอดมาจากคลาสที่ปิดผนึก (และเช่นคลาส. NET จำนวนมากจะถูกปิดผนึก)
วิธีเดียวที่จะบรรลุสิ่งที่คล้ายกันใน C # คือการเขียนประเภทของเราในคลาสใหม่:
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();
}
ในขณะนี้จะใช้งานได้มันเป็น verbose มากเพียง typedef นอกจากนี้เรามีปัญหาเกี่ยวกับการทำให้เป็นอนุกรม (เช่น Json) เนื่องจากเราต้องการทำให้เป็นอนุกรมของคลาสผ่านคุณสมบัติการเขียน
ด้านล่างนี้เป็นคลาสผู้ช่วยที่ใช้ "รูปแบบเทมเพลตที่เกิดซ้ำ" เพื่อทำให้สิ่งนี้ง่ายขึ้นมาก:
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 คลาสดังกล่าวจะกลายเป็น:
sealed Class SomeTypeTypeDef : Composer<SomeTypeTypeDef, SomeType> {
public SomeTypeTypeDef(SomeType composed) : base(composed) {}
// proxy the methods we want
public void Method() => Composed.Method();
}
และนอกจากนี้SomeTypeTypeDef
จะทำให้เป็นอนุกรมกับ Json ในลักษณะเดียวกับที่SomeType
ทำ
หวังว่านี่จะช่วยได้!