Implementing a BinaryOperationBinder

May 12, 2009 at 7:47 AM

I have my own BinaryOperationBinder and am using the following handler for the "Add" method, in which I'm trying to get it to use the "String" add method when one of runtime types is a string, else the default one, however in some cases the result of a string + double or string + integer ends up as a null result, this only happens in some cases so I'm thinking I'm providing the wrong BindingRestrictions for this method all together. I tried multiple variants of combining BindingRestrictions but I would like to know what's the right way of doing this. So what do I provide so it does it the right way, preferably it should call this handler for every different set of runtime type pairs (not the original expressions)?

DynamicMetaObject AddHandler(DynamicMetaObject target, arg)
{
  var lOriginal = new DynamicMetaObject[] {target, arg};
  if (target.LimitType == typeof(String) || arg.LimitType == typeof(String)) {
    arg = FBinder.ConvertTo(typeof(Object), ConversionResultKind.ImplicitCast, arg);
    target = FBinder.ConvertTo(typeof(Object), ConversionResultKind.ImplicitCast, target);
    BindingRestrictions lBinding;

    // lBinding = BindingRestrictions.GetTypeRestriction(lOriginal[0].Expression, lOriginal[0].LimitType)
    // lBinding = lBinding.Merge(BindingRestrictions.GetTypeRestriction(lOriginal[0].Expression, lOriginal[0].LimitType));

    lBinding = BindingRestrictions.Combine(lOriginal);
    return new DynamicMetaObject(Expression.Call(typeof(StringExtensions).GetMethod("Add"),
      Expression.Dynamic(fBinder.CreateConversionOperationBinder(typeof(String), false), typeof(String), target.Expression),
      Expression.Dynamic(fBinder.CreateConversionOperationBinder(typeof(String), false), typeof(String), arg.Expression)),
      lBinding);
  } else
  if ((target.LimitType == typeof(Double)|| (arg.LimitType == typeof(Double)) {
    // If one is a double, convert both
    target = fBinder.ConvertTo(typeof(Double), ConversionResultKind.ImplicitCast, target);
    arg = fBinder.ConvertTo(typeof(Double), ConversionResultKind.ImplicitCast, arg);
  }
   
  return fBinder.DoOperation("Add", target, arg);
  if (result.LimitType.IsValueType)
    return new DynamicMetaObject(Expression.Convert(result.Expression, typeof(Object)), result.Restrictions);
}

Coordinator
May 12, 2009 at 4:12 PM

I believe:

// lBinding = BindingRestrictions.GetTypeRestriction(lOriginal[0].Expression, lOriginal[0].LimitType)
// lBinding = lBinding.Merge(BindingRestrictions.GetTypeRestriction(lOriginal[0].Expression, lOriginal[0].LimitType));

Should be:

lBinding = BindingRestrictions.GetTypeRestriction(lOriginal[0].Expression, lOriginal[0].LimitType)
lBinding = lBinding.Merge(BindingRestrictions.GetTypeRestriction(lOriginal[1].Expression, lOriginal[1].LimitType));

The key here being that we’re restricting both target & arg instead of just target.  You’ll want the same restrictions for the double/double case as well – if you don’t restrict that case as well then you could end up re-using that rule – I doubt that’s what’s happening here as you’d get a invalid cast exception because you convert them to doubles.

From: carlokok [mailto:notifications@codeplex.com]
Sent: Tuesday, May 12, 2009 12:47 AM
To: Dino Viehland
Subject: Implementing a BinaryOperationBinder [dlr:56006]

From: carlokok

I have my own BinaryOperationBinder and am using the following handler for the "Add" method, in which I'm trying to get it to use the "String" add method when one of runtime types is a string, else the default one, however in some cases the result of a string + double or string + integer ends up as a null result, this only happens in some cases so I'm thinking I'm providing the wrong BindingRestrictions for this method all together. I tried multiple variants of combining BindingRestrictions but I would like to know what's the right way of doing this. So what do I provide so it does it the right way, preferably it should call this handler for every different set of runtime type pairs (not the original expressions)?

DynamicMetaObject AddHandler(DynamicMetaObject target, arg)
{
var lOriginal = new DynamicMetaObject[] {target, arg};
if (target.LimitType == typeof(String) || arg.LimitType == typeof(String)) {
arg = FBinder.ConvertTo(typeof(Object), ConversionResultKind.ImplicitCast, arg);
target = FBinder.ConvertTo(typeof(Object), ConversionResultKind.ImplicitCast, target);
BindingRestrictions lBinding;

// lBinding = BindingRestrictions.GetTypeRestriction(lOriginal[0].Expression, lOriginal[0].LimitType)
// lBinding = lBinding.Merge(BindingRestrictions.GetTypeRestriction(lOriginal[0].Expression, lOriginal[0].LimitType));

lBinding = BindingRestrictions.Combine(lOriginal);
return new DynamicMetaObject(Expression.Call(typeof(StringExtensions).GetMethod("Add"),
Expression.Dynamic(fBinder.CreateConversionOperationBinder(typeof(String), false), typeof(String), target.Expression),
Expression.Dynamic(fBinder.CreateConversionOperationBinder(typeof(String), false), typeof(String), arg.Expression)),
lBinding);
} else
if ((target.LimitType == typeof(Double)|| (arg.LimitType == typeof(Double)) {
// If one is a double, convert both
target = fBinder.ConvertTo(typeof(Double), ConversionResultKind.ImplicitCast, target);
arg = fBinder.ConvertTo(typeof(Double), ConversionResultKind.ImplicitCast, arg);
}

return fBinder.DoOperation("Add", target, arg);
if (result.LimitType.IsValueType)
return new DynamicMetaObject(Expression.Convert(result.Expression, typeof(Object)), result.Restrictions);
}

Read the full discussion online.

To add a post to this discussion, reply to this email (dlr@discussions.codeplex.com)

To start a new discussion for this project, email dlr@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

May 13, 2009 at 9:57 AM

Thanks! That did it