2013-08-05 109 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)); 

當然,在這種情況下,只有當參數類型和返回類型相同時,這纔會起作用。

相關問題