One-liner 言語としての C# 3.0 はきっとその域に達している
id:siokoshou:20070901#p2 がおもしろかったので C# コンパイラのメソッドルックアップをチェックするコードを書いてみました.
(from mi in new MethodInfo[]{ Reflector.Function<string>.Bind((Base _b, string _s) => () => _b.Method(_s)), Reflector.Function<string>.Bind((Derived _d, string _s) => () => _d.Method(_s)), Reflector.Function<string>.Bind((Hoge _h, string _s) => () => _h.Method(_s)) } let paramTypeStrs = from pi in mi.GetParameters() select pi.ParameterType.ToString() let paramStr = paramTypeStrs.Aggregate( (accum, next) => accum + " -> " + next ) select mi.DeclaringType + "." + mi.Name + " : " + paramStr + " -> " + mi.ReturnType).ToList().ForEach(Console.WriteLine);
嘘ですごめんなさい.普通に書くならこんな感じ.id:NyaRuRu:20070826:p2 で書いた Strong-typed reflection も再掲.
using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Collections.Generic; public class Program { public static void Main() { var funcs = new MethodInfo[] { Reflector.Function<string>.Bind((Base _b, string _s) => () => _b.Method(_s)), Reflector.Function<string>.Bind((Derived _d, string _s) => () => _d.Method(_s)), Reflector.Function<string>.Bind((Hoge _h, string _s) => () => _h.Method(_s)) }; var seq = from mi in funcs let paramTypeStrs = from pi in mi.GetParameters() select pi.ParameterType.ToString() let paramStr = paramTypeStrs.Aggregate((accum, next) => accum + " -> " + next) select mi.DeclaringType + "." + mi.Name + " : " + paramStr + " -> " + mi.ReturnType; // (追記) 上の文字列連結はこちらの方がベター? // let paramStr = String.Join( " -> ", paramTypeStrs.ToArray() ) seq.ToList().ForEach(Console.WriteLine); Console.ReadKey(); } } public class Base { public virtual string Method(string s) { return "Base.Method(string)"; } } public class Derived : Base { public override string Method(string s) { return "Derived.Method(string)"; } public virtual string Method(object o) { return "Derived.Method(object)"; } } public class Hoge { public string Method(string s) { return "Hoge.Method(string)"; } public string Method(object o) { return "Hoge.Method(object)"; } } public static class Reflector { static MethodInfo GetMethodInfo(this Expression expression) { var findfunc = null as Func<Expression, MethodInfo>; findfunc = expr => { switch (expr.NodeType) { case ExpressionType.Lambda: return findfunc((expr as LambdaExpression).Body); case ExpressionType.Quote: return findfunc((expr as UnaryExpression).Operand); case ExpressionType.Call: var mce = expr as MethodCallExpression; return mce != null ? mce.Method : null; case ExpressionType.MemberAccess: var me = expr as MemberExpression; var pi = me.Member as PropertyInfo; return pi != null ? pi.GetGetMethod(true) : null; default: return null; } }; return findfunc(expression); } public sealed class Function<TResult> { public static MethodInfo Bind( Expression<Func<Expression<Func<TResult>>>> expr) { return expr.GetMethodInfo(); } public static MethodInfo Bind<TArg0>( Expression<Func<TArg0, Expression<Func<TResult>>>> expr) { return expr.GetMethodInfo(); } public static MethodInfo Bind<TArg0, TArg1>( Expression<Func<TArg0, TArg1, Expression<Func<TResult>>>> expr) { return expr.GetMethodInfo(); } public static MethodInfo Bind<TArg0, TArg1, TArg2>( Expression<Func<TArg0, TArg1, TArg2, Expression<Func<TResult>>>> expr) { return expr.GetMethodInfo(); } } public sealed class Function { public static MethodInfo Bind<TArg0>( Expression<Func<TArg0, Expression<Action>>> expr) { return expr.GetMethodInfo(); } public static MethodInfo Bind<TArg0, TArg1>( Expression<Func<TArg0, TArg1, Expression<Action>>> expr) { return expr.GetMethodInfo(); } public static MethodInfo Bind<TArg0, TArg1, TArg2>( Expression<Func<TArg0, TArg1, TArg2, Expression<Action>>> expr) { return expr.GetMethodInfo(); } public static MethodInfo Bind<TArg0, TArg1, TArg2, TArg3>( Expression<Func<TArg0, TArg1, TArg2, TArg3, Expression<Action>>> expr) { return expr.GetMethodInfo(); } } }
LINQ 構文でだらだらと書いて改行潰せばワンライナーなので,それなりにその域には達しちゃった言語なのかもしれません.まあ LISP みたいなのは別格としても,C あたりの構文からスタートして,よくぞここまで練り上げた,と.
LINQ 構文のために大量に簡約ルールを追加したのもありますが,裏方サポートとして,id:NyaRuRu:20070827:p2 で書いたように「式」が増えたのと,Extension Method の導入によって method chain が楽になったのも大きいかな.
とはいえ,コマンドラインから直接叩くことを考えると,C# では参照設定や using 前提なのが邪魔だったりするのかも.