BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News C# 11 and .NET 7 Bring Generic Parsing

C# 11 and .NET 7 Bring Generic Parsing

One of the basic design patterns in .NET is the static Parse function. Virtually every class that can be instantiated from a string representation has one. Yet before C# 11 and .NET 7, there was no way to create an interface that accommodated this.

The fundamental problem is before now, abstract interfaces (i.e. the interface keyword) didn’t support static functions. This wasn’t just a C# limitation, the CLR itself didn’t support it before the introduction of the Static Abstract Methods in interfaces feature.

As with interface methods, Static Abstract Methods can have a default implementation, but there are limitations.

The static virtual and static abstract methods declared in interfaces don't have a runtime dispatch mechanism analogous to virtual or abstract methods declared in classes. Instead, the compiler uses type information available at compile time. Therefore, static virtual methods are almost exclusively declared in generic interfaces.

The example we are going to discuss today is the IParsable<TSelf> interface. It offers two methods, Parse and TryParse. Both accept a String and an IFormatProvider. To access them, you need a generic helper method such as:

static T Parse<T>(string s, IFormatProvider? provider)
    where T : IParsable<T>
{
    return T.Parse(s, provider);
}

You can invoke it using a type parameter.

var a = Parse<int>("4", null);

If you aren’t ready to upgrade to .NET 7, you can simulate it using reflection.

static T Parse<T>(string s, IFormatProvider? provider)
{
    //error handling omitted for clarity
    var type = typeof(T);
    var method = type.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, new[] { typeof(string), typeof(IFormatProvider) });
    var result = (T)method!.Invoke(null, new object?[] { s, provider })!;
    return result;
}

You can call this method in same fashion as you would the IParsable version. However, the risk in this technique is there is no compile-time safety. If the type T doesn’t have a Parse method or that method has the wrong set of parameters, the compiler can’t detect the mistake.

For performance sensitive code, you can also consider using the ISpanParsable interface. By using a Span instead of a String, memory allocations can often be avoided.

About the Author

Rate this Article

Adoption
Style

BT