2010-12-01 57 views
22

我最近遇到了這個問題,我想要一個函數來處理雙精度和整數,並且想知道爲什麼沒有用於所有數字類型(包含算術運算符和比較)的通用接口。爲什麼數字類型不共享通用接口?

它會使寫作功能如Math.Min(存在於gazillion重載)方式更方便。

會引入一個額外的接口是一個突破性的變化?

編輯: 我想用這個像

public T Add<T>(T a, T b) where T: INumber 
{ 
    return a+b; 
} 

public T Range<T>(T x, T min, T max) where T:INumber 
{ 
    return Max(x, Min(x, max), min); 
} 
+0

@Saeed:那點。 =)我的Add方法只是一個簡單的例子。就我而言,我正在對給定數組進行一些基本的統計分析,並且不關心它們是int,double,decimal還是BigIntegers,只要我可以添加它們即可。 (並且不必在許多過載中編寫這種方法) – Jens 2010-12-01 08:41:13

+0

https://referencesource.microsoft.com/#mscorlib/system/int32.cs,31 - `IArithmetic `似乎被註釋掉,可悲地:( – Caramiriel 2017-12-08 12:18:08

回答

8

如果你想要做這樣的「通用」算法,你在強類型語言如C#中的選項是非常有限的。 Marc Gravell described the problem as follows

.NET 2.0引入了泛型到.NET世界中,它爲許多優雅的解決方案打開了大門,爲現有問題打開了大門。通用約束可用於限制類型參數到已知接口等,以確保訪問功能 - 或者對於簡單的相等/不等測試,Comparer<T>.DefaultEqualityComparer<T>.Default單例分別實現IComparer<T>IEqualityComparer<T>(允許我們例如對元素進行排序,而無需瞭解任何有關問題的「T」)。

儘管如此,在運營商方面仍然存在很大差距。由於運算符聲明爲靜態方法,因此不存在所有數字類型實現的IMath<T>或類似等效接口;事實上,運營商的靈活性會使得這一切很難以有意義的方式進行。更糟糕的是:許多原始類型的操作符甚至不存在操作符;相反,有直接的IL方法。爲了使情況更加複雜,Nullable <>要求「提升運算符」的概念,其中內部「T」描述適用於可空類型的運算符 - 但這是作爲語言特徵實現的,並不由運行時(使反射更有趣)。

然而,C#4.0中引入的dynamic關鍵字,你可以用它來在運行時選擇正確的過載:

using System; 

public class Program 
{ 
    static dynamic Min(dynamic a, dynamic b) 
    { 
     return Math.Min(a, b);   
    } 

    static void Main(string[] args) 
    { 
     int i = Min(3, 4); 
     double d = Min(3.0, 4.0); 
    } 
} 

你應該知道,這消除類型安全,你可能會在運行時異常如果動態運行時無法找到合適的重載調用,例如因爲你混合類型。

如果你想要得到的類型安全,你可能想看看在MiscUtil庫基本操作提供通用的運營商提供的類。

請注意,如果您只是在特定操作之後,實際上可能會使用內置類型已實現的接口。例如,一個類型安全的泛型Min功能看起來是這樣的:

public static T Min<T>(params T[] values) where T : IComparable<T> 
{ 
    T min = values[0]; 
    foreach (var item in values.Skip(1)) 
    { 
     if (item.CompareTo(min) < 0) 
      min = item; 
    } 
    return min; 
} 
1

好了,你也看不定義接口運營商和結構(儘管它們支持的接口)止跌通過接口實現工作得很好,因爲這需要裝箱和取消裝箱,這純粹是通過接口實現進行數學操作時,這當然是一個巨大的性能。

我還要強調的是,當你施放一個結構到它的界面,結果對象是你,而不是原來的結構本身進行操作的引用類型(盒裝對象):

interface IDoSomething 
{ 
    void DoSomething(); 
} 

struct MyStruct : IDoSomething 
{ 
    public MyStruct(int age) 
    { 
    this.Age = age; 
    } 

    public int Age; 

    pubblic void DoSomething() 
    { 
    Age++; 
    } 
} 

public void DoSomething(IDoSomething something) 
{ 
    something.DoSomething(); 
} 

當我通過我的結構實例,它的盒裝(成爲一個引用類型),我執行我的DoSomething操作,但我原來的結構實例不會改變。

+0

它會實際上工作,只要你「投」到一個接口,結構將被裝箱。 – leppie 2010-12-01 08:38:56

+0

看到我的答案,我的意思。 – leppie 2010-12-01 08:40:36

+0

當我調用DoSomething(ISomething東西) `方法 – 2010-12-01 08:40:49

-3

這是「強類型語言」的主要特徵。這可以在一分鐘內避免數十億的錯誤。當然,我們希望int與double是完全不同的。

4

即如何做2 + 2.35?返回4或4.35或4.349999?界面如何理解什麼是適當的輸出?你可以編寫你的擴展方法並使用重載來解決你的問題,但是如果我們想要爲所有目的設置接口,界面大​​小和查找有用函數的時間將會很困難,而接口增加了一些開銷和數字通常是基礎所以計算需要快捷的方式。

我覺得寫的擴展類是你的情況更好:

public static class ExtensionNumbers 
{ 
    public static T Range<T>(this T input, T min, T max) where T : class 
    { 
     return input.Max(input.Min(max), min); 
    } 

    public static T Min<T>(this T input, params T[] param) where T : class 
    { 
     return null; 
    } 

    private static T Max<T>(this T input, params T[] number) where T : class 
    { 
     return null; 
    }  

} 

我以前where T : class只是要編譯

0

的問題是,如何號碼存儲不同數量的類型的結構是治療基金會不同。對於初學者來說,你的錯誤是錯誤的,界面不起作用,但是我認爲你想要的是你想讓數字鬆散地輸入。

只是爲了開始你爲什麼不想這麼做考慮到整型類型是它們可以表示的值的範圍上的一對一映射,而浮點類型有一個persistence和指數組件,因爲有嬰兒多數浮點數。語言開發人員必須在語言設計中做出一些非常基本且可能導致錯誤的假設。

看看這個article關於浮點數學的更多信息。

1

與馬修的回答一起,請注意3個調用之間的差異。

void DoSomething(ref MyStruct something) 
{ 
    something.DoSomething(); 
} 

static void Main(string[] args) 
{ 
    var s = new MyStruct(10); 
    var i = (IDoSomething)s; 

    DoSomething(s); // will not modify s 
    DoSomething(i); // will modify i 
    DoSomething(ref s); // will modify s, but with no reassignment 

} 
1

它不像引入界面簡單,因爲可用的操作每個類型不同,但它們並非總是甚至均勻(即DateTime + TimeSpan => DateTime,DateTime - DateTime => TimeSpan)。

在技術層面,這裏可能涉及很多拳擊等,加上經常經營者是static

其實,對於Min/MaxComparer<T>.Default.Compare(x,y)幾乎所有你會希望的。

對於其他操作符:在.NET 4中。0 dynamic是有很大幫助的位置:

T x = ..., y = ...; 
T sum = (dynamic)x + (dynamic)y; 
通過 Operator

但除此之外, 「MiscUtil」 有generic support for operators,即

T x = ..., y = ...; 
T sum = Operator.Add(x, y); // actually Add<T> 
相關問題