簡體   English   中英

有沒有解決這種c#類型推斷失敗的方法?

[英]Is there a way around this c# type inference failure?

我有以下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排除在外,那么從檢查中就沒有任何歧義。 這里有什么問題?

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

如果我改變測試用例以正確地運用類型,那么問題就變得很明顯了

    [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可以實現這一點。

問題是你的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));

問題是沒有辦法,使用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));

當然,在這種情況下,這僅在參數類型和返回類型相同時才有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM