11

以下が可能かどうか疑問に思っていました。匿名型 (string、int、decimal、customObject など) を受け入れるクラスを作成し、Type に基づいてさまざまな操作を行うメソッドをオーバーロードします。例

    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();

これは可能ですか、それとも私はただ夢を見ているだけですか?

4

8 に答える 8

12

あなたがやろうとしていることは、次のように可能です:

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

これ可能ですが、ジェネリックの目的を無効にしています。ジェネリクスのポイントは、型が問題にならない場合にあるため、この場合、ジェネリックは適切ではないと思います。

于 2009-10-22T17:12:18.760 に答える
5

C# では、C++ のように「特殊化」することはできません。.NET ジェネリックでは、<T> のジェネリック クラスまたはメソッドは、T のすべての可能な値に対して同じでなければなりません。 >>、同じ機械語コードを共有します。(異なる値の型は別のマシン コードを取得しますが、それでも特化することはできません。)

次のような汎用インターフェイスまたは基本クラスを作成すると役立つ場合があります。

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; }
}
于 2009-10-22T17:10:44.110 に答える
4

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>()
于 2009-10-22T17:20:58.380 に答える
1

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

if/else またはスイッチを入れる必要があります

typeof(T)

特殊な実装を呼び出す。

ただし、次のように、 T の型をクラス (値の参照) または構造体 (値) または特定の基底クラスのサブクラスのいずれかに制約することができます。

 public Foo<T> DoBar<T>() where T : FooBase;
于 2009-10-22T17:12:08.497 に答える
0

BFree が述べたように、if ツリー、またはおそらく switch ステートメントを使用してこれを行うことができますが、ある時点で、特にオーバーロードのライブラリを時間をかけて成長させる場合は、メソッドを記述して .Net にそれを理解させたいと思うでしょう。 .

解決策はリフレクションですが、.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;
}

基本的には、Reflection フレームワークにその switch ステートメントを実行するように指示しているだけです。

于 2015-06-25T19:36:53.130 に答える
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
}
于 2009-10-22T17:39:08.327 に答える
0

クラス拡張メソッドを使用するとうまくいきますか?

基本的に、必要なクラスにメソッドを追加して、同じ方法で呼び出すことができます。

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

次を使用して呼び出されます:

myString.GetName();
于 2009-10-22T17:09:11.700 に答える
0

c# は、このようなディスパッチをサポートしていません。

<> 内のすべてがメソッド シグネチャの一部でない限り、これはメソッドのオーバーロードを行う正しい方法ではありません (Error'TestClass' は、同じパラメーター タイプで 'GetName' というメンバーを既に定義しています)。

于 2009-10-22T17:12:08.647 に答える