2014-10-19 32 views
1

所以,我正在從C++轉向C#(當然,不是'移動',而是訪問),我試圖移植一個C++項目作爲練習。我似乎無法找到任何引用我的特定問題的東西。我有一個模板類Rect -通用類,不同類型的運算符重載

template< class T > 
class Rect 
{ 
public: 
    Rect() {} 
    Rect(T top, T bottom, T left, T right) 
    : 
    top(top), 
    bottom(bottom), 
    left(left), 
    right(right) 
    {} 
    Rect(const Rect& rect) 
    : 
    top(rect.top), 
    bottom(rect.bottom), 
    left(rect.left), 
    right(rect.right) 
    {} 
    void Translate(float dx, float dy) 
    { 
     top += (T)dy; 
     bottom += (T)dy; 
     left += (T)dx; 
     right += (T)dx; 
    } 
    template< class T2 > 
    operator Rect<T2>() const 
    { 
     return Rect<int>((T2) top, (T2)bottom, (T2)left, (T2)right); 
    } 
    void ClipTo(const Rect& rect) 
    { 
     top = max(top, rect.top); 
     bottom = min(bottom, rect.bottom); 
     left = max(left, rect.left); 
     right = min(right, rect.right); 
    } 
public: 
    T top; 
    T bottom; 
    T left; 
    T right; 
}; 

問題是Translate(float dx,float dy)方法。看來我不能將一個float添加到'T'中,或者甚至不能使用'T'來輸入另一個變量?重載'+'運算符似乎不是答案(同樣的問題 - 類型不匹配)。我錯過了一些痛苦簡單的事情嗎?

+0

不,你不是。不幸的是,在C#中,你不能用泛型類型的參數進行算術運算;在語言中沒有辦法將T約束爲「可加」,「可多」等類型。這是目前,恕我直言,類型系統的一個缺點。 – InBetween 2014-10-19 22:10:23

+1

期待T是一個數字類型使用泛型中斷。 – RadioSpace 2014-10-19 22:14:10

+0

@RadioSpace不,它不。爲什麼呢?遵循該邏輯,任何約束都會「打破」泛型。爲什麼'T:IFoo'有什麼不同?事實上,CLR團隊已經考慮過不止一次地解決這個問題:http://stackoverflow.com/a/6695760/767890 – InBetween 2014-10-19 22:18:23

回答

0

好的..

我在下面的例子中的實際實現非常多餘。但我只是展示瞭如何擴展方法或許可以解決這個(即使只是部分)

using System; 


namespace FOOBAR 
{ 
class Program 
{ 

    static void Main(string[] args) 
    { 
     Foo<string> stringFoo = new Foo<string>("this"); 
     stringFoo.Value = "that"; 

     Foo<float> floatFoo = new Foo<float>(2f); 
     floatFoo.SetFloat(4f);//same as 

    } 

} 

class Foo<T> 
{ 
    T value; 
    public T Value { get { return value; } set { this.value = value; } } 

    public Foo(T val) 
    { 
     value = val; 
    } 
} 

public static class FooHelper //this is a class we don't use by itself 
{ 

    //this is an extension method we can use directly from the extended type (Foo<Float>) 
    public static void SetFloat(this Foo<float> floatFoo, float value) 
    { 
     floatFoo.Value = value;//this is redunant unless we do something more complicated 
    } 
} 
} 

,並在Visual Studio中,你會看到

enter image description here

和非浮動的Foo:

enter image description here

這個具體的用法非常多餘。但也許這會給你一些方向。

並且要小心我多年前訪問過XNA的c#,並且從那以後就沒有回到C++。

+0

好吧,所以我可以超載幫助方法有一個Rect 和另一個Rect (我真的只需要那兩個),對吧?我知道你的意思,@RadioSpace,關於回到C++ - 一旦我解決了一些小問題,我想我可能會在C#中停留一段時間。 – 2014-10-19 23:18:41

+0

@JoeKnowles是的,爲每個泛型做一個。有點乏味。但畢竟你是程序員 – RadioSpace 2014-10-19 23:23:13

+0

唉!我認爲我有,但我仍然遇到'類型'問題。結束了,只是把它製作成了RectF類,我只是在各地使用浮動(bfd)。 – 2014-10-20 01:40:35

0

C#不允許您在使用泛型時使用算術。解決這個問題的一種方法是使用編譯後的表達式。例如,這裏是通用加法器:

public static class Calculator<T> 
{ 
    private static readonly Func<T, T, T> add; 

    static Calculator() 
    { 
     var param1 = Expression.Parameter(typeof(T)); 
     var param2 = Expression.Parameter(typeof(T)); 
     var addLambda = Expression.Lambda<Func<T, T, T>>(
      Expression.Add(param1, param2), 
      param1, param2 
     ); 
     add = addLambda.Compile(); 
    } 

    // invoke as Calculator<T>.Add(a, b) 
    public static T Add(T a, T b) 
    { 
     return add(a, b); 
    } 
} 

這個解決方案有點笨重,但你只需要寫一次計算器類。您可以使用類似的代碼爲泛型創建其他算術和數學運算符。對於您發佈的示例,您還需要一種方法將float轉換爲T(或者只是將Translate()更改爲T)。要做轉換,你可以添加下面的計算器:

private static readonly Func<float, T> fromFloat; 

... 


// in the static constructor 
var floatParameter = Expression.Parameter(typeof(float)); 
var fromFloatLambda = Expression.Lambda<Func<float, T>>(
    Expression.Convert(floatParameter, typeof(T)), 
    floatParameter 
); 
fromFloat = fromFloatLambda.Compile(); 


// add a new method 
public static T FromFloat(T t) { return fromFloat(t); } 
+0

呵呵。我必須回去嘗試一下......同時,我想知道爲什麼我在4個小時的Binging中沒有看到這個解決方案(或類似的)。我喜歡lambdas,我不熟悉表達樹的東西。整齊。謝謝。 – 2014-10-20 01:57:21

+0

@JoeKnowles:我不知道爲什麼這方面沒有太多的信息,但是有一點。例如,我剛剛發現[這個問題](http://codereview.stackexchange.com/questions/26022/generic-calculator-and-generic-number)和[this library](http://www.yoda.arachsys .com/csharp/miscutil/usage/genericoperators.html)(引用前面的註釋)。不幸的是,你必須知道答案才能找到答案。 – ChaseMedallion 2014-10-20 13:38:06