2017-08-02 98 views
1

我是C#的新手,嘗試將差異限制應用於模板類型時遇到了一些實際問題。也許這是不可能的,我可以從我的研究中找到的唯一的「Where」子句更多地基於走向另一個方向(即「可分配來自」)。我列出了我試圖效仿的Scala函數 - 關鍵是要確保T可分配給U(即T <:U),所以無論如何返回值都是U.任何幫助或C#方差提示理解,謝謝你從Scala的選項C#方差返回類型

interface Option<out T> // where T : class 
    { 
     T GetUnsafe(); 
     Option<X> map<X>(Func<object,Option<X>> f); 
     U GetOrElse<U>(U u) where T:U ; //What is wrong here,how do I get U:>T ? 

     bool IsSome { get; } 
    } 

實施例[A] 最終DEF getOrElse [B>:A](默認值:⇒B):乙

作爲更新,這裏有一個工作版本的靜態函數 - 我只是無法弄清楚是否有可能作爲一種方法

static class Option 
    { 
     public static U GetOrElse<T, U>(Option<T> o, U defAns) where T : U 
     { 
      if (o.IsSome) return o.GetUnsafe(); else return defAns; 
     } 
+1

爲了這個工作,你需要在界面而不是方法上聲明'U'。 – juharr

+0

如前所述,方差僅適用於接口的類型參數。無論如何,你想要的方法的約束是無效的(你只能約束方法的類型參數繼承一些類)。這就是說,恕我直言,有這樣的方法是一個尷尬的設計。爲什麼這個方法不能返回'T'?對於有'Option '的人來說,用一個類型參數調用一個方法'GetorElse ()'可能只會是'T'的一個基類型,對於一個有什麼好處呢?你的問題看起來很像[XY問題](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。 –

+0

@PeterDuniho我知道這可能看起來很奇怪,但這不是我的發明,scala完全是這樣。這裏有一個例子說明爲什麼U需要這樣綁定 - 比如說這個對象是一些,但是現在它已被上傳到我的代碼中處理選項的地方,而沒有知道任何內容。我在那個時候發出的電話必須確保U是內部項目的超類型,否則將是完全錯誤的。 Var Cat = myCat.getOrElse(new Cat)..如果它沒有界限:Var Cat = myCat.getOrElse(123455)將是一個問題 – LaloInDublin

回答

1

首先你似乎與「泛型類型約束」混合「通用方」。是的,與Java或Scala不同的C#在一個方向上僅支持繼承相關的類型約束:您可以指定基類(但您可以執行Scala或Java支持,例如new約束)。有關詳細信息,請參見where (generic type constraint) (C# Reference)。並且由於T在外部作用域中定義,所以不能在內部作用域中對其添加其他約束。這就是你的例子不能編譯的原因。第二個使用靜態方法的示例編譯,因爲C#編譯器足夠聰明,可以在聲明中重新排序泛型類型,使其看起來像使用已知類型(U)定義約束(對於T)。

我不知道什麼是getOrElse Scala的方法是設計鑑於Option是協也就是說,如果你想獲得B類型的值,即使它的實際類型A剛剛宣佈你var的現實生活中的使用因爲型號爲Option[B]。所以我認爲不復制這一點邏輯不是一大損失。

通常我不認爲您可以輕鬆地複製這樣的代碼,從Scala保留到C#的行爲,但對於此方法只有一個您不需要重寫的固定實現的特定情況,您可以擴展您靜態招用extension methods

public static class OptionHelper 
{ 
    public static U GetOrElse<T, U>(this Option<T> o, U defAns) 
     where T : U 
    { 
     if (o.IsSome) return o.GetUnsafe(); else return defAns; 
    } 
} 

因爲額外this關鍵字的參數,然後才能使用它,就好像它在接口本身定義(類似於一個位中的默認的Java 8的方法,你可以得到使用隱含了什麼轉換在斯卡拉):

Option<string> o = ..; 
object value = o.GetOrElse(new object()); 
+0

謝謝,看起來靜態函數是解決這些問題的最佳方法 – LaloInDublin