私は多くのユニットテストを行っており、ほとんど同じ動作をテストしています。ただし、データ型は変更されます。
任意のデータ型を取ることができるジェネリックメソッドを作成しようとしています。入力パラメーターをvarにしようとしましたが、これは許可されていません。また、c#ジェネリックを調べましたが、通常はリストを扱います。
パラメータをobject
にすることができます:
_public void DoSomething(object arg)
{
//...
_
または、あなたが私が好むことをして、一般的な方法を作ることができます:
_public void DoSomething<T>(T arg)
{
//...
_
一般的なアプローチには2つの主要な利点があります。それらが役立つ理由の例を示します。
arg
のタイプを明示的に指定していなくても、アクセスできます。逆に、object
アプローチにはいくつかの重要な欠点があります。
arg
をobject
として扱っているため、anyオブジェクトで実行できることしか実行できません。object
パラメータとして渡すと、変数は boxed になり、パフォーマンスに影響します。大したヒットではありませんが、DoSomething
を数千回続けて呼び出すと、感じ始めるかもしれません。ジェネリックメソッドに型制約を追加すると、特定の型のみを受け入れるようにメソッドを制限できます。なぜそれが役立つのですか?作業している特定のタイプがわからない(または気にしていない)場合でも、そのタイプについて何か知っているので、その情報を使用できます。
次の設定を検討してください。
_public interface IAnimal
{
void Move();
}
public class Duck : IAnimal
{
public void Move()
{
Console.WriteLine("Flying");
}
}
public class Fish : IAnimal
{
public void Move()
{
Console.WriteLine("Swimming");
}
}
public class Ant : IAnimal
{
public void Move()
{
Console.WriteLine("Walking");
}
}
_
IAnimal
インターフェイスがあるので、IAnimal
の実装anyを対象としたジェネリックメソッドを記述できます。
_public class Program
{
static void DoMove<T>(T animal) where T : IAnimal
{
animal.Move();
}
public static void Main(string[] args)
{
Duck duck = new Duck();
Fish fish = new Fish();
Ant ant = new Ant();
DoMove<Duck>(duck);
DoMove<Fish>(fish);
DoMove<Ant>(ant);
}
}
_
実行: http://rextester.com/GOF1761
DoMove
メソッドを記述するとき、そのパラメーターanimal
がDuck
、Fish
、Ant
であるかどうかは関係ありません、またはその他。重要なのは、animal.Move()
を呼び出すことだけです。 _where T : IAnimal
_制約を使用したので、コンパイラーは知る必要があるすべてを知っています。
animal
のタイプはT
です。T
が何であれ、IAnimal
を実装します。IAnimal
を実装するものには、Move()
メソッドがあります。animal.Move()
を安全に呼び出すことができます。(ちなみに、はい、DoMove
をstatic void DoMove(IAnimal animal)
と書くこともできますが、それは別の議論です。)
結構ですが、さらに一歩進めましょう。多くの場合、型パラメーターを指定せずにジェネリックメソッドを呼び出すことができます。これは type inference と呼ばれ、いくつかの入力を節約するだけでなく、異なるタイプのオブジェクトに対して同じ操作を行う場合に役立ちます。
_public static void Main(string[] args)
{
IAnimal[] animals = new IAnimal[]
{
new Duck(),
new Fish(),
new Ant()
};
foreach (IAnimal animal in animals)
{
DoMove(animal);
}
}
_
実行してください: http://rextester.com/OVKIA12317
_DoMove<T>
_メソッドを1回記述するだけで、より具体的な型を指定しなくても、任意の型のIAnimal
で呼び出すことができます。 _DoMove<T>
_がT
に使用するタイプを推測できるため、適切なバージョンのMoveが毎回呼び出されます。 DoMove(duck)
を呼び出すと、.NETは、あなたが本当にDoMove<Duck>(duck)
を意味することを理解し、Move
クラスのDuck
メソッドを呼び出します。
パラメータタイプとしてobject
を取り込むことができます。たぶん、ジェネリックを使うほうがいいでしょう。
void MyMethod<T>(T parm) { ... }
このように、パラメーターは実際にはユーザーが渡したタイプになります-object
や値のタイプのようにボックス化されません。
void MyTestMethod<T>(T t) { }
あなたに一般的なテスト方法を提供しますが、私が役立つことができる方法を想像することはできません。あなたは何をテストする必要がありますか?タイプT
にこれらのメソッドがあることをどのようにして知っていますか? T
は、上記のメソッドではanyタイプにすることができます。上記の例でt
から呼び出すことができる唯一のメソッドは、object
の一般的なメソッドです。
実際に行う必要があるのは、テストする1つ以上のタイプに対してcommon behaviourを識別し、インターフェースを介してその動作の構文規約を定義することです。次に、ジェネリックテストメソッドを制約して、そのインターフェイスを実装する型のみを受け入れることができます。
interface IMyInterface
{
void DoSomething();
}
void MyTestMethod<T>(T t) where T : IMyInterface
{
t.DoSomething();
}
public void YourMethod<T>(T parameter)
{
}
動的キーワードを使用してみてください。これは、すべての異なるタイプがユニットテストで使用されるものと同じメソッドを持っている場合に機能します。それ以外の場合は、ランタイム例外が発生します。