При использовании ключевого слова dynamic
вам необходимо знать имя метода во время компиляции, однако то, во что он в действительности компилируется, - это вызовы DLR API со строковой константой для имени метода.Конечно, это можно назвать самим, но тут сложнее то, что производительность dlr зависит от статических сайтов кэширования, созданных вместе с этими вызовами API.
Фреймворк с открытым исходным кодом ImpromptuInterface (находится в Nuget) обертывает API DLR с помощью некоторых статических методов вызова .Он хэширует сайты кеширования, поэтому он не так быстр, как динамическое ключевое слово, но по крайней мере в 2 раза быстрее, чем отражение.Единственная хитрость заключается в том, что если вы пытаетесь вызвать метод возврата void, ожидающий значение, он генерирует исключение при попытке связывания.Пример реализации:
public static dynamic SuperDuperInvoke(object target, string methodName, params object[] args){
try{
return Impromptu.InvokeMember(target, methodName, args);
}catch(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException){
Impromptu.InvokeMemberAction(target, methodName, args);
return null;
}
}
Поскольку это открытый исходный код (лицензия Apache), вы всегда можете обратиться к источнику InvokeMember и т. Д. , чтобы помочь реализовать ваш SuperDuperInvoke
, если вы не хотитезависимость.
SuperDuperInvoke2
сложнее, потому что DLR попытается сопоставить метод, основанный на типах аргументов, он будет учитывать неявные преобразования, но только статически определять их (TryConvert
на DynamicObject
не сработает), поэтому вам понадобится прокси, который имеет статически определенные неявные преобразования во все ваши ожидаемые типы, что может быть опасно, если вы перегрузите методы, они, вероятно, будут неоднозначными для SuperDuperInvoke2
.
public static dynamic SuperDuperInvoke2(object target, string methodName, params ConvertableProxy[] args){
return SuperDuperInvoke(target,methodName,args);
}
public class ConvertableProxy{
private IConvertible _value;
public ConvertableProxy(IConvertible value){
_value =value;
}
//Automatically convert strings to proxy
public static implicit operator ConvertableProxy(string value){
return new ConvertableProxy(value);
}
public static implicit operator bool(ConvertableProxy proxy)
{
return proxy._value.ToBoolean(null);
}
public static implicit operator int(ConvertableProxy proxy)
{
return proxy._value.ToInt32(null);
}
public static implicit operator string(ConvertableProxy proxy)
{
return proxy._value.ToString(null);
}
//.. Add Char, DateTime, etc.
}