c#中是否有类似的类型定义,或者以某种方式获得类似的行为?我在谷歌上搜了一下,但到处都是否定的。目前我的情况类似如下:

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型。如果能简化一下就好了……

编辑:ie。也许是对EventHandler进行类型定义,而不需要重新定义它来获得类似的行为。


当前回答

这是它的代码,享受吧!,我从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"};
        }
    }
}

其他回答

我会做

using System.Collections.Generic;
global using CustomerList = List<Customer>;

c++和c#都缺少创建与现有类型在语义上完全相同的新类型的简单方法。我发现这样的“typedefs”对于类型安全编程来说是完全必要的,c#没有内置它们真是太遗憾了。void f(string connectionID, string username)和void f(ConID connectionID, username username)之间的区别是明显的…

(你可以在c++中通过BOOST_STRONG_TYPEDEF中的boost实现类似的功能)

使用继承可能很诱人,但它有一些主要的局限性:

它不适用于基本类型 派生类型仍然可以被转换为原始类型,即我们可以将它发送给接收原始类型的函数,这违背了整个目的 我们不能从密封类中派生(即许多.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();
}

虽然这可以工作,但对于一个类型定义来说是非常冗长的。 此外,我们还有一个序列化(即Json)的问题,因为我们想通过它的compose属性序列化类。

下面是一个助手类,它使用“奇怪的重复模板模式”来简化这一点:

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一样。

希望这能有所帮助!

Jon给出了一个很好的解决方案,我不知道你能做到!

有时我要做的是从类继承并创建它的构造函数。如。

public class FooList : List<Foo> { ... }

不是最好的解决方案(除非您的程序集被其他人使用),但它是有效的。

c#支持一些事件委托的继承协方差,所以像这样的方法:

void LowestCommonHander( object sender, EventArgs e ) { ... } 

可以用来订阅您的事件,没有显式强制转换所需

gcInt.MyEvent += LowestCommonHander;

你甚至可以使用lambda语法,智能感知将为你完成:

gcInt.MyEvent += (sender, e) =>
{
    e. //you'll get correct intellisense here
};

我认为没有类型定义。你只能在GenericClass中定义一个特定的委托类型,而不是泛型委托类型。

public delegate GenericHandler EventHandler<EventData>

这会使它更短。但是下面的建议怎么样:

使用Visual Studio。这样,当你打字的时候

gcInt.MyEvent += 

它已经从智能感知中提供了完整的事件处理程序签名。按TAB键,它就在那里。接受生成的处理程序名称或更改它,然后再次按TAB键自动生成处理程序存根。