3

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; } 
7
  • 1
    Have you tried using typeof(ExpandoObject) for your ??? - I doubt it will work but worth checking...? Regardless, please could you update the question with an MVCE (yes - a non-compiling one with a placeholder marked as ???) so that we can try out solutions (and more easily understand the exact nature of your question) ourselves before suggesting them :) Commented May 4, 2018 at 16:52
  • Worth explaining (with simple example code) what you are trying to achieve. Dynamic (as a "type") is compile time thing, you cannot create it at runtime (I'd even say that this, as a concept, doesn't make sense). Commented May 4, 2018 at 17:00
  • @RB I'm not sure ExpandoObject would fill the bill... the object isn't always an anonymous type, and if I remember correctly, one of the other things dynamic can do is (somehow) act as a wrapper around a concrete type (sounds sort of like boxing-for-objects). Commented May 4, 2018 at 19:10
  • @Evk I understand that, but there must be something that "marks" the resulting object as "dynamic-capable" for lack of a better term. So in effect, I'm looking for a way to do the same thing at runtime. I won't be too surprised if it simply isn't possible, but I wanted a more authoritative answer than, "I couldn't figure it out." :) Commented May 4, 2018 at 19:14
  • 1
    If it helps to understand: aside from one attribute, Func<dynamic, object> M() => n => new { n.prop }; compiles to the exact same IL as Func<object, object> M() => n => new { ((dynamic) n).prop };. dynamic property access is implemented by calls to the DLR and is completely different from the direct property access using reflection you're used to. Commented May 4, 2018 at 20:24

1 Answer 1

3

It's not possible to do that via reflection, because dynamic concept only exists at compile time, not a run time.

If you compile something like:

dynamic x = "test"; Console.WriteLine(x.Length); 

And decompile result in something like DotPeek - you'll see quite a bunch of cryptic, reflection-like code to which compiler has converted your dynamic code. And x is really of type object, so the whole thing is basically similar to typeof(string).GetProperty("Length").GetValue(x), but maybe more effective. But nowhere you will see any trace of dynamic itself.

So, there is no way to somehow obtain Func<dynamic, object> from Func<T, object> at runtime.

Foo<dynamic>(n => new { n.prop }); 

Is conceptually similar to something like:

Foo<object>((object n) => new { prop = n.GetType().GetProperty("prop").GetValue(n) }); 

I've unfortunately didn't quite understood your use case, though I tried, so cannot give reasonable advice about what to use instead.

Sign up to request clarification or add additional context in comments.

2 Comments

I suppose the "reflection-like code" is interaction with the dynamic language runtime as mentioned by user hvd in the comments after the question? Makes sense. Good enough as a better explanation than "I just can't get it to work!"
@McGuireV10 in certain sense. It uses types from System.Runtime.CompilerServices, such as CallSite, Binder and so on. With certain efforts you can manually write such code, and mimic behavior of compiler.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.