我有以下IObserver的C#扩展方法。它使我能够通过使用中间主题将LINQ表达式放在首位。
/// <summary>
/// Given an IObserver we may wish to build a new IObserver that has LINQ
/// combinators at it's head.
///
/// observer = observer.Wrap(observable=>observable.Where(k=>k>0));
///
/// </summary>
public static IObserver<U>
Wrap<T,U>
( this IObserver<T> This
, Func<IObservable<U>, IObservable<T>> fn
)
{
var s = new Subject<U>();
fn(s).Subscribe(This);
return s;
}
但是当我使用方法时
[Fact]
public void WrapShouldWrapObservers()
{
var b = new List<int>() { 0, 1, 2,3,4,5 };
var s = new Subject<int>();
var c = new List<int>();
var obs = s.Wrap(observable => observable.Where(k => k > 3));
s.Subscribe(v => c.Add(v));
b.ToObservable().Subscribe(obs);
c.Should().BeEquivalentTo(4, 5);
}
我收到错误
Error 2 The type arguments for method
ReactiveUI.Ext.IObservableMixins.Wrap<T,U>
( System.IObserver<T>
, System.Func<System.IObservable<U>,System.IObservable<T>>
)
cannot be inferred from the usage. Try specifying the type arguments
explicitly.
当我明确地输入类型args然后它可以工作。
var obs = s.Wrap<int,int>(observable => observable.Where(k => k > 3));
然而,如果我将类型args退出,那么从检查中就没有歧义。这有什么问题?
----------- ------------ ANSWER
如果我更改测试用例以正确运用类型,那么问题就变得很明显了
[Fact]
public void WrapShouldWrapObservers()
{
var b = new List<int>() { 0, 1, 2,3,4,5 };
var s = new Subject<string>();
var c = new List<string>();
var obs2 = s.Wrap<int,string>(observable => observable.Where(k => k > 3).Select(k=>k.ToString()));
s.Subscribe(v => c.Add(v));
b.ToObservable().Subscribe(obs2);
c.Should().BeEquivalentTo("4", "5");
}
无法知道lambda的第一个参数应该是observable
。 lambda必须返回IObservable,但是有无数种类型的observable可以实现这一点。
答案 0 :(得分:1)
问题是你的lambda中的观察者可以是任何类型。如果您打算使用无法转换类型的LINQ运算符,您可以这样做:
public static IObserver<T> Wrap<T> (this IObserver<T> this,
Func<IObservable<T>, IObservable<T>> fn)
{
var s = new Subject<T>();
fn(s).Subscribe(this);
return s;
}
否则,您必须采用不同的方式,指定IObserver
类型:
var obs = s.Wrap((IObserver<int> observer) => observer.Where(k => k > 3));
答案 1 :(得分:0)
问题是没有办法,使用lambda表达式从参数中推断出类型U
。
你可以通过在其他地方指定表达式类型来解决这个问题:
Func<IObservable<int>, IObservable<int>> wrapper = o => o.Where(k => k > 3);
var obs = s.Wrap(wrapper);
或者这个
private IObservable<int> Wrapper(IObservable<int>> o)
{
return o.Where(k => k > 3);
}
var obs = s.Wrap(this.Wrapper);
你也可以通过创建一个不同的重载来解决这个问题,可以从参数中推断
:public static IObserver<T> Wrap<T>
( this IObserver<T> This
, Func<IObservable<T>, IObservable<T>> fn )
{
return This.Wrap<T, T>(fn);
}
var obs = s.Wrap(observer => observer.Where(k => k > 3));
当然在这种情况下,只有在参数类型和返回类型相同时才会起作用。