C ++과 C # 모두 기존 형식과 의미가 동일한 새 형식 을 만드는 쉬운 방법이 없습니다 . 나는 타입 안전 프로그래밍에 꼭 필요한 'typedefs'를 발견하고 실제 수치는 c #에 내장되어 있지 않습니다. 의 차이 void f(string connectionID, string username)
로는 void f(ConID connectionID, UserName username)
분명하다 ...
(BOOST_STRONG_TYPEDEF를 높이면 C ++에서 비슷한 것을 얻을 수 있습니다)
상속을 사용하고 싶을 수도 있지만 몇 가지 중요한 제한이 있습니다.
- 기본 유형에는 작동하지 않습니다
- 파생 된 유형은 여전히 원래 유형으로 캐스트 될 수 있습니다. 즉, 원래 유형을받는 함수에 보낼 수 있습니다.
- 봉인 된 클래스에서 파생 될 수 없습니다 (즉, 많은 .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();
}
이것이 효과가 있지만 typedef에 대해서는 매우 장황합니다. 또한 Composed 속성을 통해 클래스를 직렬화하려는 경우 직렬화 (예 : 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
.
도움이 되었기를 바랍니다 !