一般的な印刷機能が必要です... PrintGeneric(T)...次の場合、何が欠けていますか?
いつものようにあなたの助け/洞察は高く評価されています...
public interface ITest
{}
public class MyClass1 : ITest
{
public string myvar = "hello 1";
}
public class MyClass2 : ITest
{
public string myvar = "hello 2";
}
class DoSomethingClass
{
static void Main()
{
MyClass1 test1 = new MyClass1();
MyClass2 test2 = new MyClass2();
Console.WriteLine(test1.myvar);
Console.WriteLine(test2.myvar);
Console.WriteLine(test1.GetType());
PrintGeneric(test1);
PrintGeneric<test2.GetType()>(test2);
}
// following doesn't compile
public void PrintGeneric<T>(T test)
{
Console.WriteLine("Generic : " + test.myvar);
}
}
Tは何でもかまいませんし、すべてがmyvar
フィールドを持つわけではないので、コンパイルしません。
myvar
をITest
のプロパティにすることができます:
public ITest
{
string myvar{get;}
}
プロパティとしてクラスに実装します:
public class MyClass1 : ITest
{
public string myvar{ get { return "hello 1"; } }
}
次に、メソッドに汎用制約を設定します。
public void PrintGeneric<T>(T test) where T : ITest
{
Console.WriteLine("Generic : " + test.myvar);
}
しかし、その場合、正直に言うと、ITestを渡すだけの方が良いでしょう。
public void PrintGeneric(ITest test)
{
Console.WriteLine("Generic : " + test.myvar);
}
少なくともいくつかのことが欠けています:
リフレクションを使用していない限り、型引数はコンパイル時に認識される必要があるため、使用できません
PrintGeneric<test2.GetType()>
...この場合、とにかくする必要はありませんが
PrintGeneric
は現在T
について何も知らないため、コンパイラはT
というメンバーを見つけることができません。
オプション:
ITest
インターフェイスにプロパティを配置し、PrintGeneric
を変更してT
を制約します。
public void PrintGeneric<T>(T test) where T : ITest
{
Console.WriteLine("Generic : " + test.PropertyFromInterface);
}
ITest
インターフェイスにプロパティを配置し、ジェネリックを完全に削除します。
public void PrintGeneric(ITest test)
{
Console.WriteLine("Property : " + test.PropertyFromInterface);
}
C#4を使用している場合は、ジェネリックの代わりに動的型付けを使用します
ジェネリックメソッドでは、T
は型の単なるプレースホルダーです。ただし、コンパイラーは、ランタイムで使用されている具象型については何も知らないため、var
メンバーがあるとは想定できません。
これを回避する通常の方法は、メソッド宣言にジェネリック型制約を追加して、使用する型が特定のインターフェイスを実装することを保証することです(場合によっては、ITest
になります)。
public void PrintGeneric<T>(T test) where T : ITest
その後、そのインターフェイスのメンバーはメソッド内で直接利用可能になります。ただし、ITest
は現在空です。メソッド内での使用を有効にするには、そこで一般的なものを宣言する必要があります。
ジェネリック型T
に関する詳細情報を提供する必要があります。現在のPrintGeneric
メソッドでは、T
はstring
メンバーを持たないvar
である場合もあります。
var
をフィールドではなくプロパティに変更できます
public interface ITest
{
string var { get; }
}
そして、制約を追加しますwhere T: ITest
をPrintGeneric
メソッドに。
次のような、インターフェースで何かを定義する必要があります。
public interface ITest
{
string Name { get; }
}
クラスにITest
を実装します。
public class MyClass1 : ITest
{
public string Name { get { return "Test1"; } }
}
public class MyClass2 : ITest
{
public string Name { get { return "Test2"; } }
}
次に、汎用のPrint
関数をITest
に制限します。
public void Print<T>(T test) where T : ITest
{
}
試してみる
public void PrintGeneric<T>(T test) where T: ITest
{
Console.WriteLine("Generic : " + test.@var);
}
@Ash Burlaczenkoは、キーワードの後に変数の名前を付けることはできないと言っています。
ジェネリックではvar
にアクセスできません。
のようなものを試してください
Console.WriteLine("Generic : {0}", test);
ToString
メソッドをオーバーライドします[1]
[1] http://msdn.Microsoft.com/en-us/library/system.object.tostring.aspx