3 votes

Accès aux membres des types de valeurs génériques en C#

J'écris un programme C# qui effectue des calculs dans plusieurs systèmes de coordonnées, et des transformations entre eux. Pour éviter toute confusion, j'aimerais utiliser un type de valeur statique distinct pour chaque type de coordonnées :

struct FooSpaceCoords {
    double x, y, z;
}

struct BarSpaceCoords {
    double x, y, z;
}

Maintenant, une classe de matrice pratique et sûre serait bien. Mais ce qui suit ne peut pas fonctionner :

 public class MatrixTransform<To, From> where To : struct, From : struct 
 {
    .... some implementation that requires .x, .y and .z ....
 }

Cela échoue car le compilateur ne peut pas savoir que To y From ont des membres .x , .y & .z .

Je pourrais définir un IHaveXYZ mais il me semble que cela entraînera de nombreuses opérations de boxe, ce qui va à l'encontre de l'esprit de l'ensemble du plan (et est moins efficace, si cela compte).

Existe-t-il un moyen simple de faire ce que je voulais à l'origine ?

3voto

Jon Skeet Points 692016

Je pourrais définir une interface IHaveXYZ, mais il me semble que cela entraînerait un grand nombre d'opérations de boxe, ce qui va à l'encontre de l'esprit de l'ensemble du plan (et est moins efficace, si cela compte).

Non, ce n'est pas le cas. Si vous utilisez une contrainte de type générique, l'IL généré sera no box/unbox. Par exemple :

interface IFoo
{
    void Foo();
}

struct Bar : IFoo
{
    public void Foo()
    {
        // Do something
    }
}

class Test
{
    static void DoFoo<T>(T value) where T : IFoo
    {
        value.Foo();
    }

    static void Main()
    {
        Bar bar = new Bar();
        DoFoo(bar); // No boxing involved
    }
}

L'IL pour DoFoo ressemble à ça :

.method private hidebysig static void  DoFoo<(IFoo) T>(!!T 'value') cil managed
{
  // Code size       16 (0x10)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarga.s   'value'
  IL_0003:  constrained. !!T
  IL_0009:  callvirt   instance void IFoo::Foo()
  IL_000e:  nop
  IL_000f:  ret
} // end of method Test::DoFoo

Notez la partie "contrainte". Extrait de l'ECMA-335 section I.8.2.4 :

La mise en boîte et le déballage des arguments génériques ajoutent une surcharge de performance à une implémentation CLI. Le site constrained. Le préfixe peut améliorer les performances lors de l'envoi virtuel vers une méthode définie par un type de valeur, en évitant de mettre en boîte le type de valeur.

Il est important que vous Ne le fais pas. il suffit de se référer à value como IFoo cependant. Cette ligne serait box la valeur (lorsque T est une catégorie de valeur) :

IFoo copy = value; // Might box

Tant que vous vous en tenez au paramètre de type générique, tout devrait bien se passer.

1voto

Sriram Sakthivel Points 33463

Implémenter une interface commune pour les deux structs et changer les champs en propriétés.

interface ISomething
{
    Double X{ get;}
    Double Y{ get;}
    Double Z{ get;}
}

puis ajoutez cette interface comme contrainte générique. Vous avez terminé

Note : comme @Jon l'a fait remarquer, les contraintes génériques n'encadreront pas les valuetypes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X