Необходимо использовать isinstance
isinstance(...)
isinstance(object, class-or-type-or-tuple) -> bool
Return whether an object is an instance of a class or of a subclass thereof.
With a type as second argument, return whether that is the object's type.
The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for
isinstance(x, A) or isinstance(x, B) or ... (etc.).
Это похоже на:
Вам необходимо сопоставить возвращаемый тип, указанный свойством ReturnType
. Для всех стандартных двоичных файлов это фиксировано для объекта почти для всего или недействительно (для операций удаления). Если вы знаете, что делаете вызов void, я бы посоветовал обернуть его в:
Expression.Block(
call,
Expression.Default(typeof(object))
);
DLR был довольно небрежным в отношении того, что он допускал, и автоматически обеспечивал минимальное количество принуждения. Мы избавились от этого, потому что не хотели предоставлять набор условных обозначений, которые могли иметь или не иметь смысла для каждого языка.
Похоже, вы хотите предотвратить:
dynamic x = obj.SomeMember();
Нет способа сделать это, всегда будет возвращаться значение, с которым пользователь может попытаться продолжить динамическое взаимодействие.
Мне это не нравится, но вроде работает; реальная проблема, похоже, заключается в том, что binder.ReturnType
появляется странно (и не отбрасывается ("всплывает") автоматически), но:
if (target.Type != binder.ReturnType) {
if (target.Type == typeof(void)) {
target = Expression.Block(target, Expression.Default(binder.ReturnType));
} else if (binder.ReturnType == typeof(void)) {
target = Expression.Block(target, Expression.Empty());
} else {
target = Expression.Convert(target, binder.ReturnType);
}
}
return new DynamicMetaObject(target, restrictions);
Возможно, call-сайт ожидает возврата null, но отбрасывает результат - Это перечисление выглядит интересно, особенно флаг «ResultDiscarded» ...
[Flags, EditorBrowsable(EditorBrowsableState.Never)]
public enum CSharpBinderFlags
{
BinaryOperationLogical = 8,
CheckedContext = 1,
ConvertArrayIndex = 0x20,
ConvertExplicit = 0x10,
InvokeSimpleName = 2,
InvokeSpecialName = 4,
None = 0,
ResultDiscarded = 0x100,
ResultIndexed = 0x40,
ValueFromCompoundAssignment = 0x80
}
Пища для размышлений ...
ОБНОВЛЕНИЕ :
Дополнительные подсказки можно почерпнуть из Microsoft / CSharp / RuntimeBinder / DynamicMetaObjectProviderDebugView, который используется (я полагаю) в качестве визуализатора для отладчиков. Метод TryEvalMethodVarArgs проверяет делегата и создает привязку с флагом отбрасывания результата (???)
Type delegateType = Expression.GetDelegateType(list.ToArray());
if (string.IsNullOrEmpty(name))
{
binder = new CSharpInvokeBinder(CSharpCallFlags.ResultDiscarded, AccessibilityContext, list2.ToArray());
}
else
{
binder = new CSharpInvokeMemberBinder(CSharpCallFlags.ResultDiscarded, name, AccessibilityContext, types, list2.ToArray());
}
CallSite site = CallSite.Create(delegateType, binder);
... Я нахожусь в конце моего Reflector-foo, но создание этого кода кажется немного странным, поскольку сам метод TryEvalMethodVarArgs ожидает объект в качестве возвращаемого типа, а последняя строка возвращает результат динамического вызова. Я, наверное, лаю не на то [выражение] дерево.
-Oisin
Связыватель C # (в Microsoft.CSharp.dll) знает, используется ли результат; как говорит x0n (+1), он отслеживает это во флаге. К сожалению, флаг скрыт внутри экземпляра CSharpInvokeMemberBinder
, который является частным типом.
Похоже, что механизм привязки C # использует ICSharpInvokeOrInvokeMemberBinder.ResultDiscarded
(свойство внутреннего интерфейса ) прочитать; CSharpInvokeMemberBinder
реализует интерфейс (и свойство). Кажется, работа выполняется в Microsoft.CSharp.RuntimeBinder.BinderHelper.ConvertResult ()
. В этом методе есть код, который срабатывает, если вышеупомянутое свойство ResultDiscarded
не возвращает истину, если тип выражения недействителен.
Так что мне не кажется, что там »