Coder Perfect

In C#, typedef is the equivalent.

Problem

Is there a typedef equivalent in C#, or a means to achieve something similar? I’ve done some research, but everything I find is negative. I’m now in a circumstance that looks like this:

class GenericClass<T> 
{
    public event EventHandler<EventData> MyEvent;
    public class EventData : EventArgs { /* snip */ }
    // ... snip
}

It doesn’t take a rocket scientist to figure out that trying to construct a handler for that event can soon lead to a lot of typing (apologies for the terrible pun). It would end up looking like this:

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();
}

Except I was already utilizing a complex type, not just an int, in my case. It would be wonderful if this could be made a little easier…

To get comparable behavior, consider typedefing the EventHandler rather to having to redefine it.

Asked by Matthew Scharley

Solution #1

No, there isn’t a genuine typedef equivalent. Within a single file, you can utilize ‘using’ directives, for example.

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

However, this will only have an effect on the source file. In C and C++, typedef is commonly used within.h files that are extensively included, thus a single typedef can be used across an entire project. Because there is no #include mechanism in C# that allows you to include the using directives from one file in another, that ability does not exist.

Fortunately, there is a workaround in the example you provided: implicit method group conversion. You may just replace the event subscription line to:

gcInt.MyEvent += gcInt_MyEvent;

🙂

Answered by Jon Skeet

Solution #2

Jon really gave a nice solution, I didn’t know you could do that!

I had to resort to inheriting from the class and writing its constructors on occasion. E.g.

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

It’s not the best solution (unless your assembly is utilized by others), but it gets the job done.

Answered by Jonathan C Dickinson

Solution #3

You can define a class with implicit operators to convert between the alias and the actual class if you know what you’re doing.

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 };
    }
}

I don’t recommend it and have never used something like it, although it might work in some instances.

Answered by palswim

Solution #4

Both C++ and C# lack simple methods for creating new types that are semantically identical to existing types. Such ‘typedefs’ are absolutely necessary for type-safe programming in my opinion, and it’s a shame c# doesn’t have them built-in. It’s easy to see how void f(string connectionID, string username) differs from void f(ConID connectionID, UserName username).

(With boost in BOOST STRONG TYPEDEF, you can achieve something similar in C++.)

It may be tempting to employ inheritance, but there are some significant drawbacks:

In C#, the only option to achieve something comparable is to compose our type into a new class:

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();
}

While this is functional, it is overly verbose for a typedef. We also have an issue serializing (i.e. to Json) the class because we wish to serialize it using its Composed property.

To make things easier, here’s a helper class that employs the “Curiously Recurring Template Pattern”:

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);
    }
  }

}

With Composer, the above class is reduced to:

sealed Class SomeTypeTypeDef : Composer<SomeTypeTypeDef, SomeType> {
   public SomeTypeTypeDef(SomeType composed) : base(composed) {}

   // proxy the methods we want
   public void Method() => Composed.Method();
}

Furthermore, the SomeTypeTypeDef will serialize to Json in the same manner as the SomeType.

I hope this information is useful!

Answered by kofifus

Solution #5

I don’t believe there is a typedef. In the GenericClass, you could only define a specific delegate type instead of the generic one, i.e.

public delegate GenericHandler EventHandler<EventData>

It would be shorter as a result of this. However, how about the following idea:

Make use of Visual Studio. As a result, when you typed

gcInt.MyEvent += 

Intellisense has already provided the whole event handler signature. It’s there if you press TAB. Accept or alter the produced handler name, then press TAB to auto-generate the handler stub.

Answered by OregonGhost

Post is based on https://stackoverflow.com/questions/161477/equivalent-of-typedef-in-c-sharp