web-dev-qa-db-ja.com

C#:汎用オブジェクトを渡す

一般的な印刷機能が必要です... 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);
    }
}
15
user1229895

Tは何でもかまいませんし、すべてがmyvarフィールドを持つわけではないので、コンパイルしません。

myvarITestのプロパティにすることができます:

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);
}
24
jonnystoten

少なくともいくつかのことが欠けています:

  • リフレクションを使用していない限り、型引数はコンパイル時に認識される必要があるため、使用できません

    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を使用している場合は、ジェネリックの代わりに動的型付けを使用します

6
Jon Skeet

ジェネリックメソッドでは、Tは型の単なるプレースホルダーです。ただし、コンパイラーは、ランタイムで使用されている具象型については何も知らないため、varメンバーがあるとは想定できません。

これを回避する通常の方法は、メソッド宣言にジェネリック型制約を追加して、使用する型が特定のインターフェイスを実装することを保証することです(場合によっては、ITestになります)。

public void PrintGeneric<T>(T test) where T : ITest

その後、そのインターフェイスのメンバーはメソッド内で直接利用可能になります。ただし、ITestは現在空です。メソッド内での使用を有効にするには、そこで一般的なものを宣言する必要があります。

2
Péter Török

ジェネリック型Tに関する詳細情報を提供する必要があります。現在のPrintGenericメソッドでは、Tstringメンバーを持たないvarである場合もあります。

varをフィールドではなくプロパティに変更できます

public interface ITest
{
    string var { get; }
}

そして、制約を追加しますwhere T: ITestPrintGenericメソッドに。

2
C.Evenhuis

次のような、インターフェースで何かを定義する必要があります。

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
{
}
1
Moo-Juice

試してみる

public void PrintGeneric<T>(T test) where T: ITest
{
    Console.WriteLine("Generic : " + test.@var);
}

@Ash Burlaczenkoは、キーワードの後に​​変数の名前を付けることはできないと言っています。

0
Luke McGregor

ジェネリックではvarにアクセスできません。

のようなものを試してください

Console.WriteLine("Generic : {0}", test);

ToStringメソッドをオーバーライドします[1]

[1] http://msdn.Microsoft.com/en-us/library/system.object.tostring.aspx

0
nolith