是否在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进行类型定义,而不必重新定义它以获得类似的行为。
不,没有typedef的真实等效项。您可以在一个文件中使用“ using”指令,例如
using CustomerList = System.Collections.Generic.List<Customer>;
但这只会影响该源文件。在C和C ++中,我的经验是typedef
通常在广泛包含的.h文件中使用-因此,单个typedef
可以在整个项目中使用。该功能在C#中不存在,因为C#中没有#include
功能,该功能允许您将一个文件中的using
指令包含到另一个文件中。
幸运的是,您给does提供的示例已修复-隐式方法组转换。您可以将事件订阅行更改为:
gcInt.MyEvent += gcInt_MyEvent;
:)
可以使用这种基类来模拟typedef行为:
乔恩真的提供了一个很好的解决方案,我不知道您能做到这一点!
有时我求助于从类继承并创建其构造函数。例如:
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;
您甚至可以使用lambda语法,智能感知将全部为您完成:
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键以自动生成处理程序存根。
您可以使用我创建的一个开源库和一个名为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));
}
}
这里是代码,请尽情享受!,我从dotNetReference中挑选了它。在名称空间行106中键入“ using”语句http://referencesource.microsoft.com/#mscorlib/microsoft/win32/win32native.cs
using System;
using System.Collections.Generic;
namespace UsingStatement
{
using Typedeffed = System.Int32;
using TypeDeffed2 = List<string>;
class Program
{
static void Main(string[] args)
{
Typedeffed numericVal = 5;
Console.WriteLine(numericVal++);
TypeDeffed2 things = new TypeDeffed2 { "whatever"};
}
}
}
C ++和C#都缺少创建new类型的简单方法,该类型在语义上与现有类型相同。我发现这样的“ typedefs”对于类型安全的编程至关重要,而真正的可惜的是C#没有内置它们。 void f(string connectionID, string username)
与void f(ConID connectionID, UserName username)
之间的区别很明显...
(您可以通过BOOST_STRONG_TYPEDEF中的增强功能在C ++中实现类似的功能
使用继承可能很诱人,但这有一些主要限制:
在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
将以与SomeType
相同的方式序列化为Json。
需要代理方法可能很麻烦,但也因祸得福,作为一种新类型,我们通常只希望选择一些方法并将新方法添加到“ typedef”中]
希望这会有所帮助!
我在C#中找到的typedef
的最佳替代方法是using
。例如,我可以使用以下代码通过编译器标志控制浮点精度: