Created
May 23, 2024 21:54
-
-
Save MarkPflug/7623e42781fde59357c41d835046b61c to your computer and use it in GitHub Desktop.
Generic Specialization for IParsable<T>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Reflection; | |
var x = GetParser<Thing>(); | |
var y = GetParser<int>(); | |
static IParser<T> GetParser<T>() | |
{ | |
// specialize for T == Thing | |
if (typeof(T) == typeof(Thing)) | |
{ | |
if (MyThingParser.Inst is IParser<T> p) | |
{ | |
return p; | |
} | |
} | |
// maybe more specializations of T | |
// if (typeof(T) == typeof(...)) | |
// handle any generic IParsable<T> | |
var p2 = TryGetGenericParser<T>(); | |
return p2; | |
} | |
static IParser<T> TryGetGenericParser<T>() | |
{ | |
// dynamically specialize T for IParsable<T> via reflection | |
var ifaces = typeof(T).FindInterfaces(TypeFilter, typeof(T)); | |
if (ifaces.Length == 1) | |
{ | |
var i = ifaces[0]; | |
var t = typeof(GenericParser<>).MakeGenericType(i.GetGenericArguments()[0]); | |
var f = BindingFlags.Static | BindingFlags.Public; | |
var v = t.GetField("Inst", f).GetValue(null) as IParser<T>; | |
return v; | |
} | |
return null; | |
} | |
static bool TypeFilter(Type type, object o) | |
{ | |
var p = (Type)o; | |
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IParsable<>) && type.GetGenericArguments()[0] == p) | |
return true; | |
return false; | |
} | |
interface IParser<T> | |
{ | |
T Parser(string s); | |
} | |
class Thing | |
{ | |
public static readonly Thing A = new Thing(); | |
public static readonly Thing B = new Thing(); | |
} | |
// custom parser I don't own "Thing", so can't apply IParsable<T> | |
class MyThingParser : IParser<Thing> | |
{ | |
public static MyThingParser Inst = new MyThingParser(); | |
public Thing Parser(string s) | |
{ | |
return string.IsNullOrEmpty(s) ? Thing.A : Thing.B; | |
} | |
} | |
// generic parser for any IParsable<T> type. | |
class GenericParser<T> : IParser<T> where T : IParsable<T> | |
{ | |
public static readonly GenericParser<T> Inst = new GenericParser<T>(); | |
public T Parser(string s) | |
{ | |
return T.Parse(s, null); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment