web-dev-qa-db-fra.com

C #: Passer un objet générique

Je veux avoir une fonction d'impression générique ... PrintGeneric (T) ... dans le cas suivant, qu'est-ce qui me manque?

Comme toujours, votre aide/compréhension est appréciée ...

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

Il ne compile pas car T pourrait être n'importe quoi, et tout n'aura pas le champ myvar.

Vous pouvez faire de myvar une propriété sur ITest:

public ITest
{
    string myvar{get;}
}

et l'implémenter sur les classes en tant que propriété:

public class MyClass1 : ITest
{
    public string myvar{ get { return "hello 1"; } }
}

puis mettez une contrainte générique sur votre méthode:

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

mais dans ce cas, pour être honnête, il vaut mieux simplement passer un ITest:

public void PrintGeneric(ITest test)
{
    Console.WriteLine("Generic : " + test.myvar);
}
24
jonnystoten

Vous manquez au moins deux choses:

  • Sauf si vous utilisez la réflexion, les arguments de type doivent être connus au moment de la compilation, vous ne pouvez donc pas utiliser

    PrintGeneric<test2.GetType()>
    

    ... bien que dans ce cas vous n'en ayez pas besoin de toute façon

  • PrintGeneric ne sait rien de T pour le moment, donc le compilateur ne peut pas trouver un membre appelé T

Options:

  • Placez une propriété dans l'interface ITest et modifiez PrintGeneric pour contraindre T:

    public void PrintGeneric<T>(T test) where T : ITest
    {
        Console.WriteLine("Generic : " + test.PropertyFromInterface);
    }
    
  • Mettez une propriété dans l'interface ITest et supprimez entièrement les génériques:

    public void PrintGeneric(ITest test)
    {
        Console.WriteLine("Property : " + test.PropertyFromInterface);
    }
    
  • Utilisez la frappe dynamique au lieu des génériques si vous utilisez C # 4

6
Jon Skeet

Dans votre méthode générique, T n'est qu'un espace réservé pour un type. Cependant, le compilateur ne sait rien en soi sur le ou les types concrets utilisés lors de l'exécution, il ne peut donc pas supposer qu'ils auront un membre var.

La façon habituelle de contourner cela est d'ajouter une contrainte de type générique à votre déclaration de méthode pour vous assurer que les types utilisés implémentent une interface spécifique (dans votre cas, il pourrait s'agir de ITest):

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

Ensuite, les membres de cette interface seraient directement disponibles dans la méthode. Cependant, votre ITest est actuellement vide, vous devez y déclarer des éléments communs afin de permettre son utilisation dans la méthode.

2
Péter Török

Vous devrez fournir plus d'informations sur le type générique T. Dans votre méthode PrintGeneric actuelle, T pourrait aussi bien être un string, qui n'a pas de membre var.

Vous souhaiterez peut-être remplacer var par une propriété plutôt que par un champ

public interface ITest
{
    string var { get; }
}

Et ajoutez une contrainte where T: ITest à la méthode PrintGeneric.

2
C.Evenhuis

Vous devez définir quelque chose dans l'interface, comme:

public interface ITest
{
    string Name { get; }
}

Implémentez ITest dans vos classes:

public class MyClass1 : ITest
{
    public string Name { get { return "Test1"; } }
}

public class MyClass2 : ITest
{
    public string Name { get { return "Test2"; } }
}

Limitez ensuite votre fonction générique Print à ITest:

public void Print<T>(T test) where T : ITest
{
}
1
Moo-Juice

essayer

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

comme @Ash Burlaczenko a dit que vous ne pouvez pas nommer une variable après un mot-clé, si vous voulez vraiment que ce préfixe avec le symbole @ échappe au mot-clé

0
Luke McGregor

Vous ne pouvez pas accéder à var avec le générique.

Essayez quelque chose comme

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

Et remplacer la méthode ToString [1]

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

0
nolith