C#为什么这种类型的推断方法调用模糊不清?

时间:2015-07-27 17:32:22

标签: c#

以下函数对尝试复制C#6.0中可用的空条件运算符:

public static TResult Bind<T, TResult>(this T obj, Func<T, TResult> func)
    where T : class
{
    return obj == null ? default(TResult) : func(obj);
}

public static TResult Bind<T, TResult>(this Nullable<T> obj, Func<T, TResult> func)
    where T : struct
{
    return obj.HasValue ? func(obj.Value) : default(TResult);
}

第一个函数被约束到类,而String s允许我写出类似的东西:

var x = s.Bind(a => a.Substring(1));

第二个功能是我遇到麻烦的地方。例如,给定int? number我想写:

var y = number.Bind(a => a + 1);

然而,这给了我以下错误:

  

以下方法或属性之间的调用是不明确的:&#39; BindingExtensions.Bind&lt; T,TResult&gt;(T,Func&lt; T,TResult&gt;)&#39;和&#39; BindingExtensions.Bind&lt; T,TResult&gt;(T?,Func&lt; T,TResult&gt;)&#39;

我猜这与匿名函数的类型推断和方法重载决策之间的相互作用有关。如果我指定a的类型为int而不是编译就好了。

var y = number.Bind((int a) => a + 1);

然而,这显然不太理想。任何人都可以告诉我为什么编译器认为上面的绑定调用是模糊的和/或提供一种方法来解决这个问题?我知道我可以简单地命名这两个函数,但那有什么乐趣?

2 个答案:

答案 0 :(得分:2)

重载函数无法通过类型约束消除歧义(请参阅“Generic constraints, where T : struct and where T : class”)。任何可空类型N分别满足N : TN : Nullable<T>前所需的Bindnumber定义。我猜测Nullable<int>类型为var x = s.Bind(a => a.Substring(1)); 或类似。

s

这是明确的,因为string属于T类型,而string : Nullable<T>属于var y = number.Bind(a => a + 1); ,所以只有第一次重载才可以接受。

a => a + 1

这是不明确的,因为Func<int?,int?>的类型可以推断为Func<int,int>Func<int?,int?>。如果推断为Func<int,int>,则应用第一个重载,如果推断为var y = number.Bind((int a) => a + 1); ,则应用第二个重载。

number

如果Nullable<int>的类型为T,则这是明确的。对于所有T : Nullable<int>而非T : intT : int的第一次重载,所以它不适用。对于第二次重载,您只需T = int就可以轻松满足public class RippleBackground extends RelativeLayout { private ArrayList<RippleView> rippleViewList=new ArrayList<RippleView>(); private Paint paint; private AnimatorSet animatorSet; private ArrayList<Animator> animatorList; ... paint = new Paint(); rippleParams=new LayoutParams((int)(2*(rippleRadius+rippleStrokeWidth)),(int)(2*(rippleRadius+rippleStrokeWidth))); rippleParams.addRule(CENTER_IN_PARENT, TRUE); animatorSet = new AnimatorSet(); animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); animatorList=new ArrayList<Animator>(); addView(rippleView,rippleParams); rippleViewList.add(rippleView); ... animatorSet.playTogether(animatorList); private class RippleView extends View { @Override protected void onDraw(Canvas canvas) { int radius=(Math.min(getWidth(),getHeight()))/2; canvas.drawCircle(radius,radius,radius-rippleStrokeWidth,paint); } }

答案 1 :(得分:0)

试试这个:

    public static TResult Bind<T, TResult>(this T? obj, Func<T?, TResult> func)
    where T : struct
    {
        return obj.HasValue ? func(obj.Value) : default(TResult);
    }