2009-10-22 69 views
10

我想知道以下是否可能。創建一個接受匿名類型(string,int,decimal,customObject等)的類,然後重載基於類型執行不同操作的方法。例如方法重載類型C#

class TestClass<T> 
{ 
    public void GetName<string>() 
    { 
     //do work knowing that the type is a string  
    } 

    public string GetName<int>() 
    { 
     //do work knowing that the type is an int 

    } 

    public string GetName<int>(int addNumber) 
    { 
     //do work knowing that the type is an int (overloaded)  
    } 

    public string GetName<DateTime>() 
    { 
     //do work knowing that the type is a DateTime 

    } 

    public string GetName<customObject>() 
    { 
     //do work knowing that the type is a customObject type  
    } 

} 

所以,現在我可以調用GetName方法,因爲我已經在類型過去了我初始化的對象,正確的方法是發現和執行。

TestClass foo = new TestClass<int>(); 

//executes the second method because that's the only one with a "int" type 
foo.GetName(); 

這是可能的還是我只是在做夢?

回答

12

你試圖做的是可能是這樣的:

class TestClass<T> 
{ 
    public string GetName<T>() 
    { 
     Type typeOfT = typeof(T); 
     if(typeOfT == typeof(string)) 
     { 
      //do string stuff 
     } 
    } 
} 

雖然這可能的,你是那種擊敗仿製藥的目的。泛型的一點是當型不是的問題時,所以我不認爲泛型在這種情況下是合適的。

0

會使用類擴展方法嗎?

你基本上可以將方法添加到你想要的類,然後你可以用同樣的方法調用它。

namespace ExtensionMethods 
{ 
    public static class MyExtensions 
    { 
     public static int GetName(this String str) 
     { 
      ... 
     } 
    } 
} 

使用稱爲:

myString.GetName(); 
4

「專業化」,在C#是不可能的它是在C++的方式。在.NET泛型中,對於T的所有可能值,通用類或方法<T>必須相同。這允許運行時執行兩種不同參考類型的優化,例如TestClass <字符串>和TestClass <列表<int> >,共享相同的機器語言代碼。 (不同的值類型獲得單獨的機器代碼,但你仍然無法專注。)

我發現它有時幫助創建一個通用的接口或基類是這樣的:

abstract class Base<T> { 
    public abstract T GetName(); 
    // any common code goes here that does not require specialization 
} 

而且在衍生做到專業化類別:

class IntVersion : Base<int> { 
    public override int GetName() { return 1; } 
    public int GetName(int addNumber) { ... } 
} 
class StringVersion : Base<string> { 
    public override string GetName() { return "foo"; } 
} 
class DateTimeVersion : Base<DateTime> { 
    public override DateTime GetName() { return DateTime.Now; } 
} 
+0

+1 Generics!=模板 – user7116 2009-10-22 17:11:56

1

不,這是不可能的。你想要做的是類似於C++中的模板專門化,這在C#中(可惜)是不可能的。

你需要

typeof(T) 

到的if/else或開關來調用特定的實現。

但是,可以約束T的類型爲一個類(基準值)或結構(值)或特定基類的子類,像這樣:

public Foo<T> DoBar<T>() where T : FooBase; 
0

C#不具有用於支撐這種調度。

只要<>內部不是方法簽名的一部分,這也是做方法重載的不正確方法(Error'TestClass'已經定義了一個名爲'GetName'的成員具有相同的參數類型)。

3

專業化在C#中是不可能的。在C#中最接近的東西是以下內容

public void Example() { 
    public static void Method<T>(T value) { ... } 
    public static void Method(int value){ ... } 
    public static void Method(string) { ... } 
} 

C#編譯器將優先於通用方法的非泛型方法。這意味着使用int參數進行調用將綁定到int重載與通用重載之間。

Example.Method(42); // Method(int) 
Example.Method(new Class1()) // Method<T>(T) 

這會咬你,因爲這種方法一般稱爲不適用。在這種情況下,無論類型如何,它都會綁定到泛型重載。

public void Gotcha<T>(T value) { 
    Example.Method(value); 
} 

Gotcha(42); // Still calls Example.Method<T>() 
0

如果你需要在你的類中做類型特定的工作,那麼你的類不是通用的。你應該爲每個你想要處理的類型創建一個單獨的類。如果某些功能確實具有通用的理由,那麼可以將它放在通用的基類中。

一個例子:

abstract class TestClass<T> 
{ 
    public List<T> Items { get; set; } 

    // other generic (i.e. non type-specific) code 
} 

class IntTestClass : TestClass<int> 
{ 
    public string GetName() 
    { 
     // do work knowing that the type is an int 
    } 

    // other code specific to the int case 
} 

class StringTestClass : TestClass<string> 
{ 
    public string GetName() 
    { 
     // do work knowing that the type is a string 
    } 

    // other code specific to the string case 
} 
0

由於貝麗提到的,你可以,如果樹,或者更可能的switch語句有做到這一點,但在某些時候你會希望你可以只寫方法,讓淨弄明白,特別是如果你隨着時間的推移增長超負荷庫。

的解決方案有反映,雖然它是相當便宜的性能代價在.net:

using System.Reflection; 
... 

public string DoSomething(object val) 
{ 
    // Force the concrete type 
    var typeArgs = new Type[] { val.GetType() }; 

    // Avoid hard-coding the overloaded method name 
    string methodName = new Func<string, string>(GetName).Method.Name; 

    // Use BindingFlags.NonPublic instead of Public, if protected or private 
    var bindingFlags = BindingFlags.Public | BindingFlags.Instance; 

    var method = this.GetType().GetMethod(
     methodName, bindingFlags, null, typeArgs, null); 

    string s = (string)method.Invoke(this, new object[] { val }); 

    return s; 
} 

你基本上只是告訴了思考框架去做到這一點switch語句你。