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;
}
McGuireV10
  • 9,572
  • 5
  • 48
  • 64
  • 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 :) – RB. May 04 '18 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). – Evk May 04 '18 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). – McGuireV10 May 04 '18 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." :) – McGuireV10 May 04 '18 at 19:14
  • Still cannot quite understand your goal. Your code sample works as expected? If not - what is expected? – Evk May 04 '18 at 19:25
  • @Evk I added another explanatory paragraph before the code. – McGuireV10 May 04 '18 at 19:40
  • 1
    If it helps to understand: aside from one attribute, `Func M() => n => new { n.prop };` compiles to the exact same IL as `Func 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. –  May 04 '18 at 20:24

1 Answers1

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.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • 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 May 04 '18 at 20:41
  • 1
    @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. – Evk May 04 '18 at 20:47