return DynamicMetaObject.BindGetMember 的结果表达式应该怎么表示该成员不存在?
What should return the resulting expression of DynamicMetaObject.BindGetMember to express that the member does not exist?
我有这个(简化的)class,它通过 IDynamicMetaObjectProvider
:
公开了动态成员
public abstract class MyDynViewModel: ViewModelBase, IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return new MyDynViewModelDynamicMetaObject(parameter, this);
}
public object GetDynamicObject(string name)
{
return GetChild(name) ?? GetCommand(name);
}
}
这是我的(简化的)BindGetMember
方法:
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
var self = Expression.Convert(Expression, LimitType);
Expression expression;
var propertyName = binder.Name;
var args = new Expression[1];
args[0] = Expression.Constant(propertyName);
expression = Expression.Call(self, typeof(MyDynViewModel).GetMethod("GetDynamicObject", BindingFlags.Public | BindingFlags.Instance), args);
var getMember = new DynamicMetaObject(expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType));
return getMember;
}
基本上GetChild(string)
和GetCommand(string)
returnnull
如果没有匹配名字的child/command
这里发生的是,如果我在 XAML 中绑定一个不存在的 child/command 名称,绑定将成功解析为 null
值。
但是,我想要的行为是绑定没有成功解析。原因是它允许我使用 PriorityBinding
.
到目前为止,我得到了两个解决方案:
- 如果没有匹配的 child/command 名称,则抛出 RuntimeBinderException。当您尝试访问无效成员时,这就是
dynamic
对象所做的。但是我觉得这里有点太重了。
- returnDependencyProperty.UnsetValue,这样就够了
PriorityBinding
的作品(在documentation中有解释)。
但是,none 这些解决方案会导致通常的绑定错误消息:
System.Windows.Data Warning: 40 : BindingExpression path error: '****'
property not found on 'object' ''Object' (HashCode=13794971)'.
BindingExpression:Path=****; DataItem='Object' (HashCode=13794971);
target element is 'TextBlock' (Name=''); target property is 'Text'
(type 'String')
那么,有没有 idea/advice 实现此行为的最佳方法?
据我所知,最接近的是:
System.Windows.Data Error: 17 : Cannot get 'EX' value (type 'Object') from '' (type 'Test'). BindingExpression:Path=EX; DataItem='Test' (HashCode=11280399); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') InvalidOperationException:'System.InvalidOperationException: Property path is not valid. 'System.Dynamic.DynamicObject+MetaDynamic' does not have a public property named 'Items'.
现在,棘手的问题是什么。我看到你有相当复杂的代码,那是因为你正在从零开始创建一切。你有没有考虑过这个:
public class TestViewModel : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
return false; // if we didn't find member.
}
}
代替?
如果这不符合您的需要,首先,您需要修改您的 GetDynamicObject
签名,添加一个额外的参数 "result"。
您需要在 Expression
中包装功能,伪代码:
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
var self = Expression.Convert(Expression, LimitType);
Expression expression;
var propertyName = binder.Name;
var args = new Expression[1];
args[0] = Expression.Constant(propertyName);
expression = Expression.Call(self, typeof(MyDynViewModel).GetMethod("GetDynamicObject", BindingFlags.Public | BindingFlags.Instance), args);
expression = "if GetDynamicObject returned false, means we found nothing.
then we should return binder.FallbackGetMember(this, e)";
var getMember = new DynamicMetaObject(expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType));
return getMember;
}
您可以检查 PropertyPath.cs DLR 实现并跟踪它:
// Define other methods and classes here
// 6. IDynamicMetaObjectProvider
// This supports the DLR's dynamic objects
if (accessor == null &&
SystemCoreHelper.IsIDynamicMetaObjectProvider(item))
{
accessor = SystemCoreHelper.NewDynamicPropertyAccessor(
item.GetType(), propertyName);
}
我有这个(简化的)class,它通过 IDynamicMetaObjectProvider
:
public abstract class MyDynViewModel: ViewModelBase, IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression parameter)
{
return new MyDynViewModelDynamicMetaObject(parameter, this);
}
public object GetDynamicObject(string name)
{
return GetChild(name) ?? GetCommand(name);
}
}
这是我的(简化的)BindGetMember
方法:
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
var self = Expression.Convert(Expression, LimitType);
Expression expression;
var propertyName = binder.Name;
var args = new Expression[1];
args[0] = Expression.Constant(propertyName);
expression = Expression.Call(self, typeof(MyDynViewModel).GetMethod("GetDynamicObject", BindingFlags.Public | BindingFlags.Instance), args);
var getMember = new DynamicMetaObject(expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType));
return getMember;
}
基本上GetChild(string)
和GetCommand(string)
returnnull
如果没有匹配名字的child/command
这里发生的是,如果我在 XAML 中绑定一个不存在的 child/command 名称,绑定将成功解析为 null
值。
但是,我想要的行为是绑定没有成功解析。原因是它允许我使用 PriorityBinding
.
到目前为止,我得到了两个解决方案:
- 如果没有匹配的 child/command 名称,则抛出 RuntimeBinderException。当您尝试访问无效成员时,这就是
dynamic
对象所做的。但是我觉得这里有点太重了。 - returnDependencyProperty.UnsetValue,这样就够了
PriorityBinding
的作品(在documentation中有解释)。
但是,none 这些解决方案会导致通常的绑定错误消息:
System.Windows.Data Warning: 40 : BindingExpression path error: '****' property not found on 'object' ''Object' (HashCode=13794971)'. BindingExpression:Path=****; DataItem='Object' (HashCode=13794971); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
那么,有没有 idea/advice 实现此行为的最佳方法?
据我所知,最接近的是:
System.Windows.Data Error: 17 : Cannot get 'EX' value (type 'Object') from '' (type 'Test'). BindingExpression:Path=EX; DataItem='Test' (HashCode=11280399); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') InvalidOperationException:'System.InvalidOperationException: Property path is not valid. 'System.Dynamic.DynamicObject+MetaDynamic' does not have a public property named 'Items'.
现在,棘手的问题是什么。我看到你有相当复杂的代码,那是因为你正在从零开始创建一切。你有没有考虑过这个:
public class TestViewModel : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
return false; // if we didn't find member.
}
}
代替?
如果这不符合您的需要,首先,您需要修改您的 GetDynamicObject
签名,添加一个额外的参数 "result"。
您需要在 Expression
中包装功能,伪代码:
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
var self = Expression.Convert(Expression, LimitType);
Expression expression;
var propertyName = binder.Name;
var args = new Expression[1];
args[0] = Expression.Constant(propertyName);
expression = Expression.Call(self, typeof(MyDynViewModel).GetMethod("GetDynamicObject", BindingFlags.Public | BindingFlags.Instance), args);
expression = "if GetDynamicObject returned false, means we found nothing.
then we should return binder.FallbackGetMember(this, e)";
var getMember = new DynamicMetaObject(expression, BindingRestrictions.GetTypeRestriction(Expression, LimitType));
return getMember;
}
您可以检查 PropertyPath.cs DLR 实现并跟踪它:
// Define other methods and classes here
// 6. IDynamicMetaObjectProvider
// This supports the DLR's dynamic objects
if (accessor == null &&
SystemCoreHelper.IsIDynamicMetaObjectProvider(item))
{
accessor = SystemCoreHelper.NewDynamicPropertyAccessor(
item.GetType(), propertyName);
}