13

this.value が T であるジェネリック クラスでこれを試すと、次のようになります。

if (this.value.GetType() == typeof(int))
{
    ((int)this.value)++;
}
else
{
    throw new InvalidOperationException
            ("T must be an int to perform this operation");
}

コンパイル時に次のエラーが表示されます:「型 'T' を 'int' に変換できません」

this.value が int の場合、積分演算を実行するにはどうすればよいですか?

これは単なる例であることに注意してください。このコードはジェネリックを使用して型変換を行います。「int」は T の型の 1 つの例にすぎません。

4

5 に答える 5

24

残念ながら、特定の T 実装についてコンパイラを納得させるのは非常に困難です。1つの(厄介な)アプローチは、途中でオブジェクトにキャストすることです(これにより、値の型がボックス化およびボックス化解除されることに注意してください):

int i = (int)(object)this.value;
i++;
this.value = (T)(object)i;

醜いが、それは動作します。.NET 3.5 では、一般的な算術演算用のより優れたラッパーがいくつかあります。Operator クラスはMiscUtilの一部です。最も単純なレベルでは、AddAlternative が非常にうまく機能すると思います。

this.value = Operator.AddAlternative(this.value, 1);

これにより、暗黙的な <T,int> が自動的に推測されるはずです。または、自分で追加することもできます。

this.value = Operator.AddAlternative<T,int>(this.value, 1);

利点: これは元の T を実際には気にしないため、元のコードよりも好ましいです。"T +(T,int)" をサポートする任意の型 (自分の型であっても) で機能します。

そこのどこかに隠れているChangeTypeもあると思います...

[編集] Collin K と他の人々は、アーキテクチャの意味について有効な発言をしています - しかし、実用的であるため、T が実際にそれほど重要な場合があります... しかし、本当に必要でない限り、この種の特殊化を避けることに同意します. つまり、(Collin の投稿に対する私のコメントによると)、(たとえば) Matrix<T> [for T in decimal/float/int/double/など] は、多くの場合、非常に価値があります。

于 2008-10-05T20:51:06.210 に答える
12

私の意見では、ジェネリック クラスの型固有のコードはコードの匂いです。私はそれをリファクタリングして、次のようなものを取得します。

public class MyClass<T>
{
 ...
}

public class IntClass : MyClass<int>
{
  public void IncrementMe()
  {
    this.value++;
  }
}
于 2008-10-05T21:05:52.563 に答える
3

C# の静的な型付けではそうはなりませんが、オブジェクトへのキャストでだますことができます。これを行うことはお勧めしません。おそらくアーキテクチャの問題を示していますが、とにかく:

using System;

class Foo<T>
{
  public T value;

  public void Increment()
  {
   if (value is int) value = (T)(object)(((int)(object)value)+1);
  }
}

static class Program
{
    static void Main()
    {
     Foo<int> x = new Foo<int>();
     x.Increment();
     x.Increment();
      Console.WriteLine(x.value); 
    }     
}
于 2008-10-05T20:56:17.370 に答える
0

これが、 C#4 で数値または操作の制約が本当に必要な理由です。

@Marc Gravellの答えは、これ(+1)を回避する最良の方法ですが、これがジェネリックの問題であることにイライラしています。

于 2008-10-08T07:33:06.553 に答える
0

私はあなたが何を求めているのか理解していないと思います。何かを特定の型にする必要がある場合は、おそらくジェネリックを使用しないでください。ばかげているように思えます。これはあなたが求めていることを行いますが、お勧めしません。

namespace GenericsOne
{
    using System;

class Program
{
    static void Main(string[] args)
    {
        Sample<int> one = new Sample<int>();
        one.AddFive(10);

        // yes, this will fail, it is to show why the approach is generally not a good one.
        Sample<DateTime> two = new Sample<DateTime>();
        two.AddFive(new DateTime());
    }
}

}

namespace GenericsOne
{
    using System;
public class Sample<T>
{
    public int AddFive(T number)
    {
        int junk = 0;

        try
        {
            junk = Convert.ToInt32(number);
        }
        catch (Exception)
        {
            Console.WriteLine("Nope");
        }

        return junk + 5;
    }
}
}
于 2008-10-05T20:58:50.127 に答える