以下函数对尝试复制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);
然而,这显然不太理想。任何人都可以告诉我为什么编译器认为上面的绑定调用是模糊的和/或提供一种方法来解决这个问题?我知道我可以简单地命名这两个函数,但那有什么乐趣?
答案 0 :(得分:2)
重载函数无法通过类型约束消除歧义(请参阅“Generic constraints, where T : struct and where T : class”)。任何可空类型N分别满足N : T
和N : Nullable<T>
前所需的Bind
和number
定义。我猜测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 : int
和T : 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);
}