-
-
Save takeshik/1086218 to your computer and use it in GitHub Desktop.
// Original | |
public static Expression DispatchMethod( | |
Expression instance, | |
IEnumerable<MethodBase> methods, | |
IList<Type> typeArguments, | |
IList<Expression> arguments | |
) | |
{ | |
return methods | |
.Select(m => m is MethodInfo && ((MethodInfo) m).IsExtensionMethod() | |
? new Candidate(null, m, null, arguments.StartWith(instance).ToArray()) | |
: new Candidate(instance, m, null, arguments) | |
) | |
.If(_ => typeArguments != null && typeArguments.Any(), s => s | |
.Where(_ => _.MethodBase != null && _.MethodBase.IsGenericMethodDefinition && _.MethodBase.GetGenericArguments().Length == typeArguments.Count) | |
.Select(_ => _.Method.MakeGenericMethod(typeArguments.ToArray()) | |
.Let(m => new Candidate(_.Instance, m, m.GetGenericParameterMap(), arguments)) | |
) | |
) | |
.Where(t => t.Instance != null ^ (t.MethodBase.IsStatic || t.Constructor != null) | |
&& t.MethodBase.GetParameters().If(_ => t.MethodBase.IsParamArrayMethod(), | |
ps => t.Arguments.Count >= ps.Length - 1 | |
&& ps.SkipLast(1).Zip(t.Arguments, | |
(p, a) => IsAppropriate(p.ParameterType, a.Type) | |
).All(_ => _) | |
&& EnumerableEx.Repeat(ps.Last()).Zip(t.Arguments.Skip(ps.Length - 1), | |
(p, a) => IsAppropriate(p.ParameterType.GetElementType(), a.Type) | |
).All(_ => _), | |
ps => t.Arguments.Count == ps.Length | |
&& ps.Zip(t.Arguments, | |
(p, a) => IsAppropriate(p.ParameterType, a.Type) | |
).All(_ => _) | |
) | |
) | |
.Select(t => t | |
.If(_ => _.MethodBase != null && _.MethodBase.IsGenericMethod, _ => | |
InferTypeArguments(t.MethodBase.GetParameters().Select(p => p.ParameterType), t.Arguments.Select(e => e.Type)) | |
.Let(m => new Candidate(_.Instance, _.Method.MakeGenericMethod(m.Values.ToArray()), m, _.Arguments)) | |
) | |
.If(_ => _.MethodBase.IsParamArrayMethod(), _ => | |
_.MethodBase.GetParameters().Let(ps => | |
ps.Last().ParameterType.GetElementType().Let(et => | |
new Candidate(_.Instance, _.MethodBase, _.TypeArgumentMap, _.Arguments | |
.Take(ps.Length - 1) | |
.Concat(EnumerableEx.Return(Expression.NewArrayInit(et, _.Arguments | |
.Skip(ps.Length - 1) | |
.Select(e => e.TryConvert(et)) | |
))) | |
.ToArray() | |
) | |
) | |
) | |
) | |
) | |
.OrderBy(t => t.MethodBase.IsParamArrayMethod()) | |
.ThenBy(t => t.Method != null && t.Method.IsExtensionMethod()) | |
.ThenByDescending(t => t.TypeArgumentMap.Count) | |
.FirstOrDefault() | |
.Null(_ => _.If( | |
t => t.Method != null, | |
t => t.Instance != null | |
? (Expression) Expression.Call(t.Instance, t.Method, t.Arguments) | |
: Expression.Call(t.Method, t.Arguments), | |
t => Expression.New(t.Constructor, t.Arguments) | |
)); | |
} | |
// .NET Reflector 7.3.0.18 | |
public static Expression DispatchMethod(Expression instance, IEnumerable<MethodBase> methods, IList<Type> typeArguments, IList<Expression> arguments) | |
{ | |
return (from t in (from m in methods select ((m is MethodInfo) && ((MethodInfo) m).IsExtensionMethod()) ? ((IEnumerable<Candidate>) ((Func<MethodBase, Candidate>) new Candidate(null, m, null, arguments.StartWith<Expression>(instance).ToArray<Expression>()))) : ((IEnumerable<Candidate>) ((Func<MethodBase, Candidate>) new Candidate(instance, m, null, arguments)))).If<IEnumerable<Candidate>>(_ => (typeArguments != null) && typeArguments.Any<Type>(), (Func<IEnumerable<Candidate>, IEnumerable<Candidate>>) (s => (from _ in s | |
where ((_.MethodBase != null) && _.MethodBase.IsGenericMethodDefinition) && (_.MethodBase.GetGenericArguments().Length == typeArguments.Count) | |
select _.Method.MakeGenericMethod(typeArguments.ToArray<Type>()).Let<MethodInfo, Candidate>(m => new Candidate(_.Instance, m, m.GetGenericParameterMap(), arguments))))) | |
where !((t.Instance != null) ^ (t.MethodBase.IsStatic || (t.Constructor != null))) ? ((IEnumerable<Candidate>) ((Func<Candidate, bool>) false)) : ((IEnumerable<Candidate>) ((Func<Candidate, bool>) t.MethodBase.GetParameters().If<ParameterInfo[], bool>(_ => t.MethodBase.IsParamArrayMethod(), ps => (((t.Arguments.Count >= (ps.Length - 1)) && ps.SkipLast<ParameterInfo>(1).Zip<ParameterInfo, Expression, bool>(t.Arguments, (p, a) => IsAppropriate(p.ParameterType, a.Type)).All<bool>(_ => _)) && EnumerableEx.Repeat<ParameterInfo>(ps.Last<ParameterInfo>()).Zip<ParameterInfo, Expression, bool>(t.Arguments.Skip<Expression>((ps.Length - 1)), (p, a) => IsAppropriate(p.ParameterType.GetElementType(), a.Type)).All<bool>(_ => _)), ps => ((t.Arguments.Count == ps.Length) && ps.Zip<ParameterInfo, Expression, bool>(t.Arguments, (p, a) => IsAppropriate(p.ParameterType, a.Type)).All<bool>(_ => _))))) | |
select t.If<Candidate>(_ => ((_.MethodBase != null) && _.MethodBase.IsGenericMethod), ((Func<Candidate, Candidate>) (_ => InferTypeArguments(from p in t.MethodBase.GetParameters() select p.ParameterType, from e in t.Arguments select e.Type).Let<Dictionary<Type, Type>, Candidate>(m => new Candidate(_.Instance, _.Method.MakeGenericMethod(m.Values.ToArray<Type>()), m, _.Arguments))))).If<Candidate>(_ => _.MethodBase.IsParamArrayMethod(), (Func<Candidate, Candidate>) (_ => _.MethodBase.GetParameters().Let<ParameterInfo[], Candidate>(ps => ps.Last<ParameterInfo>().ParameterType.GetElementType().Let<Type, Candidate>(et => new Candidate(_.Instance, _.MethodBase, _.TypeArgumentMap, _.Arguments.Take<Expression>((ps.Length - 1)).Concat<Expression>(EnumerableEx.Return<NewArrayExpression>(Expression.NewArrayInit(et, (IEnumerable<Expression>) (from e in _.Arguments.Skip<Expression>(ps.Length - 1) select e.TryConvert(et))))).ToArray<Expression>()))))) into t | |
orderby t.MethodBase.IsParamArrayMethod(), (t.Method != null) && t.Method.IsExtensionMethod(), t.TypeArgumentMap.Count descending | |
select t).FirstOrDefault<Candidate>().Null<Candidate, Expression>(_ => _.If<Candidate, Expression>(t => (t.Method != null), t => ((t.Instance != null) ? ((Func<Candidate, Expression>) Expression.Call(t.Instance, t.Method, t.Arguments)) : ((Func<Candidate, Expression>) Expression.Call(t.Method, t.Arguments))), t => Expression.New(t.Constructor, t.Arguments))); | |
} | |
// ILSpy version 1.0.0.1000 | |
public static Expression DispatchMethod(Expression instance, IEnumerable<MethodBase> methods, IList<Type> typeArguments, IList<Expression> arguments) | |
{ | |
return ( | |
from t in ( | |
from m in methods | |
select (m is MethodInfo && ((MethodInfo)m).IsExtensionMethod()) ? new Dispatcher.Candidate(null, m, null, arguments.StartWith(instance).ToArray<Expression>()) : new Dispatcher.Candidate(instance, m, null, arguments)).If((IEnumerable<Dispatcher.Candidate> _) => typeArguments != null && typeArguments.Any<Type>(), (IEnumerable<Dispatcher.Candidate> s) => | |
from _ in s | |
where _.MethodBase != null && _.MethodBase.IsGenericMethodDefinition && _.MethodBase.GetGenericArguments().Length == typeArguments.Count | |
select _.Method.MakeGenericMethod(typeArguments.ToArray<Type>()).Let((MethodInfo m) => new Dispatcher.Candidate(_.Instance, m, m.GetGenericParameterMap(), arguments))) | |
where (t.Instance != null ^ (t.MethodBase.IsStatic || t.Constructor != null)) && t.MethodBase.GetParameters().If((ParameterInfo[] _) => t.MethodBase.IsParamArrayMethod(), delegate(ParameterInfo[] ps) | |
{ | |
int arg_E1_0; | |
if (t.Arguments.Count >= ps.Length - 1) | |
{ | |
if (ps.SkipLast(1).Zip(t.Arguments, (ParameterInfo p, Expression a) => Dispatcher.IsAppropriate(p.ParameterType, a.Type)).All((bool _) => _)) | |
{ | |
arg_E1_0 = (EnumerableEx.Repeat<ParameterInfo>(ps.Last<ParameterInfo>()).Zip(t.Arguments.Skip(ps.Length - 1), (ParameterInfo p, Expression a) => Dispatcher.IsAppropriate(p.ParameterType.GetElementType(), a.Type)).All((bool _) => _) ? 1 : 0); | |
return arg_E1_0 != 0; | |
} | |
} | |
arg_E1_0 = 0; | |
return arg_E1_0 != 0; | |
} | |
, delegate(ParameterInfo[] ps) | |
{ | |
bool arg_6C_0; | |
if (t.Arguments.Count == ps.Length) | |
{ | |
arg_6C_0 = ps.Zip(t.Arguments, (ParameterInfo p, Expression a) => Dispatcher.IsAppropriate(p.ParameterType, a.Type)).All((bool _) => _); | |
} | |
else | |
{ | |
arg_6C_0 = false; | |
} | |
return arg_6C_0; | |
} | |
) | |
select t.If((Dispatcher.Candidate _) => _.MethodBase != null && _.MethodBase.IsGenericMethod, (Dispatcher.Candidate _) => Dispatcher.InferTypeArguments( | |
from p in t.MethodBase.GetParameters() | |
select p.ParameterType, t.Arguments.Select((Expression e) => e.Type)).Let((Dictionary<Type, Type> m) => new Dispatcher.Candidate(_.Instance, _.Method.MakeGenericMethod(m.Values.ToArray<Type>()), m, _.Arguments))).If((Dispatcher.Candidate _) => _.MethodBase.IsParamArrayMethod(), (Dispatcher.Candidate _) => _.MethodBase.GetParameters().Let((ParameterInfo[] ps) => ps.Last<ParameterInfo>().ParameterType.GetElementType().Let((Type et) => new Dispatcher.Candidate(_.Instance, _.MethodBase, _.TypeArgumentMap, _.Arguments.Take(ps.Length - 1).Concat(EnumerableEx.Return<NewArrayExpression>(Expression.NewArrayInit(et, | |
from e in _.Arguments.Skip(ps.Length - 1) | |
select e.TryConvert(et)))).ToArray<Expression>())))) into t | |
orderby t.MethodBase.IsParamArrayMethod(), t.Method != null && t.Method.IsExtensionMethod(), t.TypeArgumentMap.Count descending | |
select t).FirstOrDefault<Dispatcher.Candidate>().Null((Dispatcher.Candidate _) => _.If((Dispatcher.Candidate t) => t.Method != null, (Dispatcher.Candidate t) => (t.Instance != null) ? Expression.Call(t.Instance, t.Method, t.Arguments) : Expression.Call(t.Method, t.Arguments), (Dispatcher.Candidate t) => Expression.New(t.Constructor, t.Arguments))); | |
} | |
// dotPeek 1.0.0.2545 | |
public static Expression DispatchMethod(Expression instance, IEnumerable<MethodBase> methods, IList<Type> typeArguments, IList<Expression> arguments) | |
{ | |
return Extension.Null<Dispatcher.Candidate, Expression>(Enumerable.FirstOrDefault<Dispatcher.Candidate>((IEnumerable<Dispatcher.Candidate>) Enumerable.ThenByDescending<Dispatcher.Candidate, int>(Enumerable.ThenBy<Dispatcher.Candidate, bool>(Enumerable.OrderBy<Dispatcher.Candidate, bool>(Enumerable.Select<Dispatcher.Candidate, Dispatcher.Candidate>(Enumerable.Where<Dispatcher.Candidate>(Extension.If<IEnumerable<Dispatcher.Candidate>>(Enumerable.Select<MethodBase, Dispatcher.Candidate>(methods, (Func<MethodBase, Dispatcher.Candidate>) (m => !(m is MethodInfo) || !Dispatcher.IsExtensionMethod((MethodInfo) m) ? new Dispatcher.Candidate(instance, (MemberInfo) m, (IDictionary<Type, Type>) null, arguments) : new Dispatcher.Candidate((Expression) null, (MemberInfo) m, (IDictionary<Type, Type>) null, (IList<Expression>) Enumerable.ToArray<Expression>(EnumerableEx.StartWith<Expression>((IEnumerable<Expression>) arguments, instance))))), (Func<IEnumerable<Dispatcher.Candidate>, bool>) (_ => typeArguments != null && Enumerable.Any<Type>((IEnumerable<Type>) typeArguments)), (Func<IEnumerable<Dispatcher.Candidate>, IEnumerable<Dispatcher.Candidate>>) (s => Enumerable.Select<Dispatcher.Candidate, Dispatcher.Candidate>(Enumerable.Where<Dispatcher.Candidate>(s, (Func<Dispatcher.Candidate, bool>) (_ => _.MethodBase != (MethodBase) null && _.MethodBase.IsGenericMethodDefinition && _.MethodBase.GetGenericArguments().Length == typeArguments.Count)), (Func<Dispatcher.Candidate, Dispatcher.Candidate>) (_ => Extension.Let<MethodInfo, Dispatcher.Candidate>(_.Method.MakeGenericMethod(Enumerable.ToArray<Type>((IEnumerable<Type>) typeArguments)), (Func<MethodInfo, Dispatcher.Candidate>) (m => new Dispatcher.Candidate(_.Instance, (MemberInfo) m, (IDictionary<Type, Type>) Dispatcher.GetGenericParameterMap(m), arguments))))))), (Func<Dispatcher.Candidate, bool>) (t => ((t.Instance != null ? 1 : 0) ^ (t.MethodBase.IsStatic ? 1 : (t.Constructor != (ConstructorInfo) null ? 1 : 0))) != 0 && Extension.If<ParameterInfo[], bool>(t.MethodBase.GetParameters(), (Func<ParameterInfo[], bool>) (_ => Dispatcher.IsParamArrayMethod(t.MethodBase)), (Func<ParameterInfo[], bool>) (ps => t.Arguments.Count >= ps.Length - 1 && Enumerable.All<bool>(Enumerable.Zip<ParameterInfo, Expression, bool>(EnumerableEx.SkipLast<ParameterInfo>((IEnumerable<ParameterInfo>) ps, 1), (IEnumerable<Expression>) t.Arguments, (Func<ParameterInfo, Expression, bool>) ((p, a) => Dispatcher.IsAppropriate(p.ParameterType, a.Type))), (Func<bool, bool>) (_ => _)) && Enumerable.All<bool>(Enumerable.Zip<ParameterInfo, Expression, bool>(EnumerableEx.Repeat<ParameterInfo>(Enumerable.Last<ParameterInfo>((IEnumerable<ParameterInfo>) ps)), Enumerable.Skip<Expression>((IEnumerable<Expression>) t.Arguments, ps.Length - 1), (Func<ParameterInfo, Expression, bool>) ((p, a) => Dispatcher.IsAppropriate(p.ParameterType.GetElementType(), a.Type))), (Func<bool, bool>) (_ => _))), (Func<ParameterInfo[], bool>) (ps => t.Arguments.Count == ps.Length && Enumerable.All<bool>(Enumerable.Zip<ParameterInfo, Expression, bool>((IEnumerable<ParameterInfo>) ps, (IEnumerable<Expression>) t.Arguments, (Func<ParameterInfo, Expression, bool>) ((p, a) => Dispatcher.IsAppropriate(p.ParameterType, a.Type))), (Func<bool, bool>) (_ => _)))))), (Func<Dispatcher.Candidate, Dispatcher.Candidate>) (t => Extension.If<Dispatcher.Candidate>(Extension.If<Dispatcher.Candidate>(t, (Func<Dispatcher.Candidate, bool>) (_ => _.MethodBase != (MethodBase) null && _.MethodBase.IsGenericMethod), (Func<Dispatcher.Candidate, Dispatcher.Candidate>) (_ => Extension.Let<Dictionary<Type, Type>, Dispatcher.Candidate>(Dispatcher.InferTypeArguments(Enumerable.Select<ParameterInfo, Type>((IEnumerable<ParameterInfo>) t.MethodBase.GetParameters(), (Func<ParameterInfo, Type>) (p => p.ParameterType)), Enumerable.Select<Expression, Type>((IEnumerable<Expression>) t.Arguments, (Func<Expression, Type>) (e => e.Type))), (Func<Dictionary<Type, Type>, Dispatcher.Candidate>) (m => new Dispatcher.Candidate(_.Instance, (MemberInfo) _.Method.MakeGenericMethod(Enumerable.ToArray<Type>((IEnumerable<Type>) m.Values)), (IDictionary<Type, Type>) m, _.Arguments))))), (Func<Dispatcher.Candidate, bool>) (_ => Dispatcher.IsParamArrayMethod(_.MethodBase)), (Func<Dispatcher.Candidate, Dispatcher.Candidate>) (_ => Extension.Let<ParameterInfo[], Dispatcher.Candidate>(_.MethodBase.GetParameters(), (Func<ParameterInfo[], Dispatcher.Candidate>) (ps => Extension.Let<Type, Dispatcher.Candidate>(Enumerable.Last<ParameterInfo>((IEnumerable<ParameterInfo>) ps).ParameterType.GetElementType(), (Func<Type, Dispatcher.Candidate>) (et => new Dispatcher.Candidate(_.Instance, (MemberInfo) _.MethodBase, _.TypeArgumentMap, (IList<Expression>) Enumerable.ToArray<Expression>(Enumerable.Concat<Expression>(Enumerable.Take<Expression>((IEnumerable<Expression>) _.Arguments, ps.Length - 1), (IEnumerable<Expression>) EnumerableEx.Return<NewArrayExpression>(Expression.NewArrayInit(et, Enumerable.Select<Expression, Expression>(Enumerable.Skip<Expression>((IEnumerable<Expression>) _.Arguments, ps.Length - 1), (Func<Expression, Expression>) (e => Extension.TryConvert(e, et)))))))))))))))), (Func<Dispatcher.Candidate, bool>) (t => Dispatcher.IsParamArrayMethod(t.MethodBase))), (Func<Dispatcher.Candidate, bool>) (t => t.Method != (MethodInfo) null && Dispatcher.IsExtensionMethod(t.Method))), (Func<Dispatcher.Candidate, int>) (t => t.TypeArgumentMap.Count))), (Func<Dispatcher.Candidate, Expression>) (_ => Extension.If<Dispatcher.Candidate, Expression>(_, (Func<Dispatcher.Candidate, bool>) (t => t.Method != (MethodInfo) null), (Func<Dispatcher.Candidate, Expression>) (t => t.Instance != null ? (Expression) Expression.Call(t.Instance, t.Method, (IEnumerable<Expression>) t.Arguments) : (Expression) Expression.Call(t.Method, (IEnumerable<Expression>) t.Arguments)), (Func<Dispatcher.Candidate, Expression>) (t => (Expression) Expression.New(t.Constructor, (IEnumerable<Expression>) t.Arguments))))); | |
} |
Hey, jarz. Thanks for reading my (garbage) code :)
This code fragment is to select method / member from candidates, part of my embedded language
(https://github.com/takeshik/yacq , see Dispatcher.cs & Extension.cs ; note below code is removed and was rewritten),
and all methods you don't know is private extension methods.
In decompiling, they are only method calls, so I thought this (using non-standard extension methods) is not big issue.
This is only serious joke, so please don't take seriously!
takeshik, I think it's a really cool project you're working on -- I've got nothing as nifty to share with the world :)
By the way, thank you for posting this gist. I'm amazed at the power of a FOSS tool like ILSpy compared to Reflector and dotPeek.
Any way you could also run this battle through dnSpy? https://github.com/0xd4d/dnSpy. Thanks!
What references do you have for this code? MethodInfo doesn't contain IsExtensionMethod() as far as I can tell. Thanks!
I ask because I want to see how Telerik's JustDecompile compares.