2013-08-05 82 views
3

我有以下C#扩展方法的IObserver。它使我能够通过使用中间主题将LINQ表达式放在头上。有没有办法解决这个C#类型推断失败?

/// <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出来。这里有什么问题?

----------- ------------回答

如果我改变测试用例行使类型正确则变得明显发生了什么问题是

[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"); 
    } 

这是不可能知道observable的第一个参数的拉姆达应该的。 lambda必须返回IObservable,但有无数个可观察类型可以实现此目的。

回答

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)); 
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)); 

当然,在这种情况下,只有当参数类型和返回类型相同时,这才会起作用。

相关问题