С учетом подписи этого метода:
void Foo<T>(Func<T, object> expression)
Можно ли использовать отражение, чтобы создать представление типа Func<dynamic, object>
для использования с MakeGenericType
для типа аргумента expression
? «Очевидные» подходы недопустимы в синтаксисе C #, поскольку dynamic
не является ни типом, ни объектом (т. Е. typeof(dynamic)
недопустим), поэтому я не смог придумать ничего полезного для параметра ???
ниже:
Type fnType = typeof(Func<,>).MakeGenericType(new Type[] { ???, typeof(object) });
Интересно, что я могу сделать это, и он компилируется без ошибок, но компилятор сценариев выдает во время выполнения, я думаю, потому что typeof
действительно возвращает Func<object, object>
:
Type fn = typeof(Func<dynamic, object>);
По крайней мере, все, что я могу найти с помощью отражения или отладчика, кажется неотличимым от typeof(Func<object, object>)
. Конечно, я понимаю, что dynamic
- это особый случай на языке C # - закулисное «магическое» поведение черного ящика, каким-то образом привязанное к object
. Вопрос, я полагаю, в том, что делает это object
особенным, когда я пишу что-то вроде этого:
Foo<dynamic>(n => new { n.prop });
Поскольку dynamic
имеет тенденцию генерировать поток ответов "ваша архитектура отстой", я опережу их, объясняя реальный сценарий: я использую API сценариев Roslyn для загрузки и компиляции делегатов выражений из конфигурации в фильтровать, деструктурировать или иным образом изменять различные объекты (включая анонимные типы, следовательно, dynamic
), записанные в структурированный регистратор (Serilog).
Я начинаю думать, что это крайний случай, с которым отражение не может справиться. (Я надеялся избежать выражений, но мне интересно, может ли это как-то справиться.)
Редактировать: реальный код
Примеры входных данных (которые действительно работают) могут быть Sample.Account
(класс в моей тестовой консольной программе) и a => new { a.Username }
в качестве выражения преобразования для компиляции, демонстрируя общий пример структурированной регистрации класса учетной записи, хранящей имя пользователя и пароль, и вы используете деструктуризацию, чтобы удалить пароль. (Я уже заполнил ScriptingOptions
необходимыми ссылками на сборки и импортом до того, как это будет вызвано.)
Выход из этого (с использованием входов, описанных выше) будет экземпляром Func<Sample.Account, object>
. Вопрос в том, как это сделать, чтобы получить Func<dynamic, object>
как вывод (который может быть записан и скомпилирован как источник, но, насколько я могу судить, не может быть настроен с помощью отражения).
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;
}