2009-09-04 8 views
3

J'ai créé une fonction qui traite un tableau d'objets, process (Object []). Cela fonctionne sur tous les types, y compris les entiers et les flottants, à condition que vous placiez chaque élément en premier. Je voudrais que la fonction prenne aussi des éléments non encadrés, ne serait-ce que pour la mettre en boîte elle-même avant le traitement. Comment je fais ça?Fonction de prendre un tableau de type arbitraire dans C#

Je pourrais envelopper avec quelques fonctions comme le processus (int []) et le processus (float []) mais cela semble aussi un problème. J'ai essayé le processus (ValueType []) mais le compilateur sélectionne toujours le processus (Object []).

J'ai C# 2.0, mais s'il y a une bonne solution pour 3.0 je voudrais le voir.

+0

Essayez-vous d'éviter la boxe pour des raisons syntaxiques ou de performance? –

+1

Pour répondre à cette question, nous avons vraiment besoin de savoir pourquoi vous aimeriez cela (plus en détail). Si vous voulez juste la commodité d'une seule fonction, alors la réponse de Jon ci-dessous fonctionnera bien. Si vous avez peur des frais généraux de la boxe, eh bien, comme ma réponse l'indique, vous aurez probablement besoin de travailler sur le corps de la méthode, puisque le déplacement de la boxe à l'intérieur du corps de la méthode n'est pas une victoire automatique. –

Répondre

0

Réponse courte: vous ne pouvez pas (utilement) le faire. Les génériques peuvent sembler être un moyen de contourner cela, mais dès que vous utilisez réellement l'instance génériquement typée, vous la passerez aux méthodes qui doivent accepter l'objet de la classe - donc ça sera mis en boîte à l'époque (pire, ça sera boxed plusieurs fois probablement, selon votre code). Si vous voulez gagner en performance en évitant de boxer de manière générique, vous devrez travailler sur comment vous traitez ces instances et vous assurez que tout traitement peut se faire de manière sûre malgré l'approche générique - et ce n'est pas facile (voir Generic Numerics par exemple) et dépend fortement du traitement que vous devez faire.

+1

La question dit explicitement qu'il ne se soucie pas nécessairement de la boxe au sein de la méthode. Vous pouvez * utilement faire qu'une méthode accepte n'importe quel tableau (en utilisant 'Array' ou une méthode générique) plutôt que d'avoir à créer un * nouveau * tableau de type' object [] 'contenant des copies encadrées. Cela pourrait avoir des avantages en termes de commodité et de performance - avoir une seule valeur «live» en boîte à la fois peut bien signifier qu'ils ne survivent que dans gen0, alors que boxer l'ensemble du tableau pourrait finir par les pousser dans gen1. –

+0

C'est possible, mais pas très plausible. Sans voir le code, c'est difficile à dire. En général, si la performance est un problème dans la mesure où la boxe joue un rôle, il ne me semble pas judicieux d'encourager la boxe répétée et inutile et le déballage à l'intérieur des boucles internes. En tout cas, le PO a besoin d'une question plus spécifique. –

+0

Un test rapide ici (évalue 'int X (objet o) {return o == nul? 0: o.GetHashCode();}' sur chaque élément du tableau) a abouti à ce que le tableau int [] prenne un peu moins de deux fois long comme le tableau d'objet [] contenant des entiers encadrés. inclure un GC.Collect dans le benchmark augmente les timings globaux mais le tableau object [] est toujours plus rapide. Par comparaison, le tableau "pré-encadré" a une consommation de mémoire crête plus élevée ... –

0
static void T(Array a) 
    { 
     if (a is int[]) 
      Console.WriteLine("Int"); 
     else 
      if (a is float[]) 
       Console.WriteLine("Float"); 
      else 
       .... 

    } 
    static void Main(){ 
     T(new int[]{30}); 
     float[] a = { 11 }; 
     T(a); 
    } 
+0

Ce n'est pas mieux que ce que l'OP a déjà - la méthode T ne peut pas accéder aux éléments de tableaux sans boxe. –

+0

(et pour éviter toute confusion, je n'utiliserais pas le nom T pour une méthode destinée à être utilisée avec de nombreux types - ce qui est communément utilisé comme paramètre de type générique) –

+0

Les tableaux dans .net sont de type System.Array. OP a une idée fausse sur les tableaux. – adatapost

0

La boxe est implicite. Par exemple:

using System; 

namespace MyProg 
{ 
    class Program 
    { 

    private static void ParamTest(params object[] args) 
    { 
     foreach (object o in args) 
     { 
     Console.Write(o); 
     Console.WriteLine(", "); 
     } 
     Console.WriteLine(); 
    } 

    static void Main(string[] args) 
    { 
     ParamTest(1, "abc", 2.4, new object()); 
    } 
    } 
} 

imprimera

 
1, 
abc, 
2.4, 
System.Object, 

Pas générique en vue!

+0

Mais vous ne pouvez pas passer un tableau qui est * déjà * un 'float []' par exemple. –

+0

Vrai, mais la question demandait des éléments non encadrés - ce qui, je pense, impliquerait généralement des types scalaires. –

+0

@Vinjay: Je ne suis pas sûr de ce que vous voulez dire. Le fait que l'OP parle d'ajouter des surcharges pour 'int []' et 'float []' suggère qu'il veut être capable d'accepter ce genre de valeur ... –

3

Comment fonctionne le traitement? La signature de la méthode la plus évidente serait:

void ProcessArray<T>(T[] data) 

qui est littéralement « un tableau d'un type arbitraire » - bien que le type doit être connu par l'appelant à la compilation. Toutefois, en fonction de la façon dont vous utilisez les éléments, vous risquez de finir la boxe. Peut-être que c'est correct, compte tenu de la partie de votre question qui dit: "ne serait-ce que de la mettre en boîte elle-même avant de la traiter". Si vous êtes assez heureux avec cela, génial :)

Si vous pouviez donner plus de détails sur ce que vous faites, nous pourrons peut-être vous aider davantage.

+0

Downvoters: s'il vous plaît ajouter un commentaire ou votre downvote est assez inutile ... –

+0

Je suis d'accord, ce qui est avec le downvote sans aucune explication? –

0

Eh bien, techniquement, il est possible. Mais ce n'est pas recommandé, ni utile, pour des raisons évidentes. Notez qu'il fonctionne mal aussi, et ne vous permet pas de passer des tableaux directement. Pour l'amour de la curiosité et de l'étrangeté, voici l'astuce. Il utilise TypedReference et les mots-clés C# non documentés.

public void Process(__arglist) 
{ 
    var iterator = new ArgIterator(__arglist); 
    do 
    { 
     TypedReference typedReference = iterator.GetNextArg(); 
     Type type = __reftype(typedReference); 
     if (type == typeof(int)) 
     { 
      int value = __refvalue(typedReference,int); 
      // value is an int 
     } 
     else if (type == typeof(string)) 
     { 
      string value = __refvalue(typedReference,string); 
      // value is a string 
     } 
     else if (type == typeof(double)) 
     { 
      double value = __refvalue(typedReference,double); 
      // value is a double 
     } 
     // etc. 
    } 
    while (iterator.GetRemainingCount() > 0); 
} 

Vous pouvez appeler la méthode comme ça:

Process(__arglist(45, "lol", 42.5)); 

Il sera pas types de valeurs boîte/de Unbox. Mais, eh bien, oublie ça ...

Questions connexes