C #에 동등한 typedef가 있습니까, 아니면 어쨌든 비슷한 행동을 취하기 위해 어떻습니까? 인터넷 검색을 해봤지만 어디에서나 부정적인 것으로 보입니다. 현재 다음과 유사한 상황이 있습니다.
class GenericClass<T>
{
public event EventHandler<EventData> MyEvent;
public class EventData : EventArgs { /* snip */ }
// ... snip
}
이제 로켓 과학자가 해당 이벤트에 대한 핸들러를 구현하려고 할 때 많은 타이핑 (끔찍한 말장난에 대한 사과)을 초래할 수 있음을 알아내는 데 로켓 과학자가 필요하지 않습니다. 결국 다음과 같이됩니다.
GenericClass<int> gcInt = new GenericClass<int>;
gcInt.MyEvent += new EventHandler<GenericClass<int>.EventData>(gcInt_MyEvent);
// ...
private void gcInt_MyEvent(object sender, GenericClass<int>.EventData e)
{
throw new NotImplementedException();
}
내 경우에는 이미 int뿐만 아니라 복잡한 유형을 사용하고 있습니다. 이것을 조금 단순화하는 것이 가능하다면 좋을 것입니다 …
편집 : 즉. 비슷한 동작을 얻기 위해 재정의 해야하는 대신 EventHandler를 typedefing 할 수 있습니다.
답변
아니요, typedef와 동등한 것은 없습니다. 하나의 파일 내에서 ‘using’지시문을 사용할 수 있습니다. 예 :
using CustomerList = System.Collections.Generic.List<Customer>;
그러나 해당 소스 파일에만 영향을 미칩니다. C 및 C ++에서 필자의 경험은 typedef
일반적으로 광범위하게 포함 된 .h 파일 내에서 사용되므로 typedef
전체 프로젝트 에서 단일을 사용할 수 있다는 것입니다. C # #include
에는 using
한 파일 의 지시문을 다른 파일에 포함시킬 수 있는 기능이 없으므로 C #에는 해당 기능이 없습니다 .
다행스럽게도 여러분이 제공하는 예제 에는 암시 적 메소드 그룹 변환이라는 수정 사항 이 있습니다. 이벤트 구독 줄을 다음과 같이 변경할 수 있습니다.
gcInt.MyEvent += gcInt_MyEvent;
🙂
답변
존은 정말 좋은 해결책을 줬습니다.
때때로 내가 의지했던 것은 클래스에서 상속하고 생성자를 만드는 것이 었습니다. 예 :
public class FooList : List<Foo> { ... }
최상의 솔루션은 아니지만 (다른 사람이 어셈블리를 사용하지 않는 한) 작동합니다.
답변
수행중인 작업을 알고 있으면 암시 적 연산자로 클래스를 정의하여 별칭 클래스와 실제 클래스 사이를 변환 할 수 있습니다.
class TypedefString // Example with a string "typedef"
{
private string Value = "";
public static implicit operator string(TypedefString ts)
{
return ((ts == null) ? null : ts.Value);
}
public static implicit operator TypedefString(string val)
{
return new TypedefString { Value = val };
}
}
나는 실제로 이것을 보증하지 않으며 이와 같은 것을 사용하지는 않았지만 이것은 특정 상황에서 효과적 일 수 있습니다.
답변
C #은 이벤트 대리자에 대해 상속 된 공분산을 지원하므로 다음과 같은 방법이 있습니다.
void LowestCommonHander( object sender, EventArgs e ) { ... }
명시 적 캐스트가 필요하지 않은 이벤트를 구독하는 데 사용할 수 있습니다.
gcInt.MyEvent += LowestCommonHander;
람다 구문을 사용할 수도 있고 인텔리전스가 모두 수행됩니다.
gcInt.MyEvent += (sender, e) =>
{
e. //you'll get correct intellisense here
};
답변
typedef가 없다고 생각합니다. GenericClass에서 제네릭 유형 대신 특정 델리게이트 유형 만 정의 할 수 있습니다.
public delegate GenericHandler EventHandler<EventData>
이것은 더 짧아 질 것입니다. 그러나 다음 제안은 어떻습니까?
Visual Studio를 사용하십시오. 이렇게하면 입력 할 때
gcInt.MyEvent +=
이미 Intellisense의 완전한 이벤트 핸들러 서명을 제공합니다. Tab을 누르면 거기에 있습니다. 생성 된 핸들러 이름을 승인하거나 변경 한 후 Tab 키를 다시 눌러 핸들러 스텁을 자동 생성하십시오.
답변
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
.
도움이 되었기를 바랍니다 !
답변
오픈 소스 라이브러리와 내가 만든 LikeType 이라는 NuGet 패키지 를 사용하면 원하는 GenericClass<int>
동작을 얻을 수 있습니다 .
코드는 다음과 같습니다.
public class SomeInt : LikeType<int>
{
public SomeInt(int value) : base(value) { }
}
[TestClass]
public class HashSetExample
{
[TestMethod]
public void Contains_WhenInstanceAdded_ReturnsTrueWhenTestedWithDifferentInstanceHavingSameValue()
{
var myInt = new SomeInt(42);
var myIntCopy = new SomeInt(42);
var otherInt = new SomeInt(4111);
Assert.IsTrue(myInt == myIntCopy);
Assert.IsFalse(myInt.Equals(otherInt));
var mySet = new HashSet<SomeInt>();
mySet.Add(myInt);
Assert.IsTrue(mySet.Contains(myIntCopy));
}
}