Given this method signature:
void Foo<T>(Func<T, object> expression)
Is it possible to use reflection to create a type-representation of Func<dynamic, object>
to use with MakeGenericType
for the expression
argument's type? The "obvious" approaches are not valid C# syntax because dynamic
is neither a type nor an object (ie. typeof(dynamic)
is invalid), so I've not been able to come up with anything useful for the ???
parameter below:
Type fnType = typeof(Func<,>).MakeGenericType(new Type[] { ???, typeof(object) });
Interestingly, I can do this and it compiles without errors, but the script compiler throws at runtime, I think because that typeof
is really returning a Func<object, object>
:
Type fn = typeof(Func<dynamic, object>);
At least, anything I can find through reflection or the debugger seems indistinguishable from typeof(Func<object, object>)
. Of course, I realize dynamic
is a special case in the C# language -- behind-the-scenes black-box "magic" behavior somehow attached to an object
. The question, I suppose, is what makes that object
special when I write something like this:
Foo<dynamic>(n => new { n.prop });
Since dynamic
tends to generate a flurry of "your architecture sucks" replies, I'll preempt those by explaining the real-world scenario: I'm using the Roslyn Scripting API to load and compile expression delegates from configuration to filter, destructure, or otherwise alter various objects (including anonymous types, hence dynamic
) written to a structured logger (Serilog).
I am starting to think this is an edge-case that reflection just can't handle. (I've been hoping to avoid Expressions, but I'm wondering if that could pull it off somehow.)
Edit: Real Code
Sample inputs (that actually work) might be Sample.Account
(a class in my test console program) and a => new { a.Username }
as the transformation expression to compile, demonstrating a common structured-logging example of an account class storing a username and password, and you use destructuring to strip the password. (I've already populated ScriptingOptions
with the necessary assembly references and imports before this is called.)
The output from this (using the inputs described above) would be an instance of Func<Sample.Account, object>
. The question is how to do this sort of thing to obtain Func<dynamic, object>
as the output (which can be written and compiled as source, but as far as I can tell, can't be set up through reflection).
private static dynamic CompileTransformation(string transformedType, string transformation)
{
// get a Type that corresponds to namespace.type in transformedType
Type TValue = Type.GetType(transformedType) ??
AppDomain.CurrentDomain.GetAssemblies()
.Select(a => a.GetType(transformedType))
.FirstOrDefault(t => t != null);
// get a representation of Func<TValue, object>
Type funcType = typeof(Func<,>).MakeGenericType(new Type[] { TValue, typeof(object) });
// get a representation of CSharpScript.EvaluateAsync<Func<TValue, object>>()
var evalMethod = typeof(CSharpScript).GetMethods()
.FirstOrDefault(m => m.Name.Equals("EvaluateAsync") && m.IsGenericMethod)
.MakeGenericMethod(funcType);
// execute EvaluateAsync
dynamic evalTask = evalMethod.Invoke(null, new object[] { transformation, ReflectionHelper.scriptOptions, null, null, null });
dynamic compiledFunc = evalTask.GetAwaiter().GetResult();
return compiledFunc;
}