2009-10-13 6 views
3

J'ai quelques problèmes en passant une référence à un objet qui est de type générique. J'ai trouvé un moyen de contourner le problème en créant un 'objet' et en faisant référence à cela plutôt qu'à l'original - mais il me semble que cela me sent un peu. Y a-t-il un meilleur moyen ici ou dois-je vivre avec? Je comprends la première erreur mais la seconde m'échappe.Utilisation d'une référence à un objet générique en tant que paramètre

public static T Foo<T>(ref T Bar) 
{ 
    T Result; 

    // Next line gives 
    // cannot convert from 'ref T' to 'ref object' 
    Result = (T)ModifyObject (ref Bar); 

    // Next line gives 
    // A ref or out argument must be an assignable variable 
    Result = (T)ModifyObject (ref ((Object)Bar)); 

    // Works 
    Object Tmp = Bar; 
    Result = (T)ModifyObject (ref Tmp)); 

    return Result; 

} 

public static Object DoSomthing(ref Object Obj) { 
    Object Result = Activator.CreateInstance (Obj.GetType()) 
    //... 
} 

DoQuelquechose n'est pas générique car il utilise la récursion où le type d'Obj peut changer. J'essayais de ne pas utiliser la réflexion pour en appeler une version générique, mais en postant peut-être que ce serait une meilleure option?

+3

Avez-vous vraiment besoin de le transmettre par référence? Inside DoSomething, attribuez-vous à Obj? – Henrik

+0

Et idem dans Foo! –

+0

(Voir http://pobox.com/~skeet/csharp/parameters.html pour plus d'informations sur la réf.) –

Répondre

5

Le type d'un argument ref doit correspondre au type du paramètre. Vous ne pouvez pas compter sur des conversions implicites ici. Eric Lippert a un blog lié: Why do ref and out parameters not allow type variation?

+0

Alors que la première erreur est expliquée par cela. Je ne comprends pas la seconde, où je la transpose explicitement à un objet (le même type de paramètre que la fonction) avant d'appliquer l'opérateur ref. –

+1

@Courtney: Un paramètre 'ref' attend une" variable "du type déclaré, ** pas une valeur **. Vous ne pouvez pas passer 42 à un paramètre 'ref int'. Les casts fonctionnent sur des valeurs et non sur des variables. Vous devez donner à l'appelé une ** place ** pour tenir un «objet». Cet endroit ne peut pas être une variable 'int', par exemple, parce que l'appelé pourrait y ajouter une' chaîne'. –

+0

I Gotcha maintenant :) - Donc, cela signifierait que la solution que j'ai est la meilleure façon de le faire? –

0

Pour le deuxième exemple, vous aurez besoin de le jeter à une variable d'objet premier:

object obj = (object)Bar; 
Result = (T)ModifyObject (ref obj); 

Mais après la méthode est exécutée, la seule chose qui est sûr est que obj sera de type Object. C'est ce que le compilateur vous avertit.

Et le code fait sentir un peu. Si vous renvoyez un résultat de type T, je ne vois pas de raison de passer le paramètre par référence. Deuxième chose, vous n'avez pas besoin de passer une instance de votre type, par référence, afin de le créer. Cette méthode fonctionne très bien:

public static Object DoSomething(Type objType) { 
    Object Result = Activator.CreateInstance(objType) 
} 

Et enfin, si vous utilisez des médicaments génériques, alors il ne devrait pas être une raison de faire tout le casting. C'est exactement pourquoi vous utilisez un paramètre générique, pour faire de votre classe un modèle pour différents types.

3

Le second message d'erreur contient déjà une explication:

Un arbitre ou un argument out doit être une variable assignable

C'est: vous créez un nouvel objet par coulée: (Object) bar peut référencer le même objet sous-jacent, mais c'est néanmoins une valeur différente. En outre, il s'agit d'une valeur temporaire car vous ne l'avez jamais affectée à un nom de variable distinct. Ainsi, le passer par référence n'a aucun sens - tout changement à cet objet temporaire serait perdu. Ainsi, les temporaires sont strictement des valeurs: vous ne pouvez pas les assigner, ou les passer par référence.

C'est aussi pourquoi votre troisième code fonctionne: vous avez maintenant lié le résultat de la conversion à un nouveau nom et ce nom peut être utilisé comme lvalue, c'est à dire qu'il peut être changé (assigné à, passé par référence) .

Questions connexes