2009-10-22 13 views
10

次のことが可能かどうか疑問に思っていました。匿名型(文字列、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の2つの異なる参照型が最適化されます。<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!= Templates – user7116

1

いいえ、これはできません。あなたがしようとしているのは、C#ではテンプレートの特殊化に似ていますが、(悲しいことに)C#では不可能です。

/ELSEまたは特別な実装を呼び出すために

typeof(T) 

に切り替える場合は、する必要があります。

ただし、クラス(基準値)または構造体(値)、またはそのような特定の基底クラスのサブクラスのいずれかに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

BFreeは、あなたがもし、ツリー、または可能性が高い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文を行う行くためにリフレクションの枠組みを言っています。

関連する問題