web-dev-qa-db-fra.com

Est-il possible de renvoyer une référence à une variable en C #?

Puis-je renvoyer une référence à une valeur double par exemple?

Voici ce que je veux faire:

ref double GetElement()
{
   ......
   // Calculate x,y,z
   return ref doubleArray[x,y,z];
}

Pour l'utiliser comme ça

void func()
{
   GetElement()=5.0;
}

C'est comme retourner un double pointeur en C++ ... Je sais que la façon dont je l'ai écrit est incorrecte ... mais existe-t-il une bonne façon de le faire?

31
Betamoo

Les types de valeurs en C # sont toujours passés par valeur. Les objets ont toujours leur référence passée par valeur. Cela change dans le code "dangereux" comme le souligne Axarydax.

Le moyen le plus simple et le plus sûr d'éviter cette contrainte est de vous assurer que votre double est attaché à un objet d'une manière ou d'une autre.

public class MyObjectWithADouble {
    public double Element {get; set;} // property is optional, but preferred.
}

...
var obj = new MyObjectWithADouble();
obj.Element = 5.0

Je veux également faire remarquer que je suis un peu confus quant à la façon dont vous prévoyez d'attribuer un double à un tableau tridimensionnel. Vous voudrez peut-être préciser ce que vous cherchez.

Je pense que je comprends un peu mieux ce que vous allez faire maintenant. Vous souhaitez renvoyer l'emplacement de la valeur dans un tableau donné, puis pouvoir modifier la valeur à cet emplacement. Ce modèle rompt certains des paradigmes attendus de C #, donc je suggérerais d'envisager d'autres façons de réaliser ce que vous recherchez. Mais si cela a vraiment du sens de le faire, je ferais quelque chose de plus comme ceci:

public class 3dArrayLocation {public int X; public int Y; public int Z;}

...

public 3dArrayLocation GetElementLocation(...)
{
    // calculate x, y, and z
    return new 3dArrayLocation {X = x, Y = y, Z = z}
}

...

var location = GetElementLocation(...);
doubleArray[location.X, location.Y, location.Z] = 5.0;
6
StriplingWarrior

MISE À JOUR: La fonctionnalité souhaitée est désormais prise en charge dans C # 7.


Le système de type CLR prend en charge les méthodes de renvoi de référence, et j'ai écrit un prototype expérimental du compilateur C # qui prend en charge la fonctionnalité souhaitée. (Le prototype implémente également des variables locales de type ref, mais les champs de type ref sont illégaux dans le système de type CLR.)

Vous avez trouvé exactement la syntaxe que j'ai choisie pour le prototype, ce qui signifie que les grands esprits se ressemblent ou que les imbéciles ne diffèrent jamais.

Bien que le prototype fonctionne très bien, il est très peu probable que cela fasse de la barre une fonctionnalité de la prochaine version du langage C #. Très peu de clients veulent cette fonctionnalité, sa mise en œuvre est assez coûteuse, nous avons une liste aussi longue que votre bras de fonctionnalités plus importantes, et il existe d'autres façons de faire fonctionner ce genre de chose sans ajouter cette complexité au système de saisie. Ce sont tous des "points contre" énormes pour la fonctionnalité.

Par exemple, vous pouvez créer une paire de délégués:

struct Ref<T>
{
    private readonly Func<T> getter;
    private readonly Action<T> setter;
    public Ref(Func<T> getter, Action<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }
    public T Value { get { return getter(); } set { setter(value); } }
}

var arr = new int[10];
var myref = new Ref<int>(()=>arr[1], x=>arr[1]=x);
myref.Value = 10;
Console.WriteLine(myref.Value);

C'est beaucoup plus lent que la même fonctionnalité implémentée avec les retours ref, mais l'avantage est que vous pouvez faire un Ref<T> dans des endroits où la référence n'est pas légale. Par exemple, vous pouvez stocker Ref<T> dans un champ, ce que vous ne pouvez pas faire avec une méthode de renvoi de référence.

Si vous avez un scénario convaincant vraiment génial pour lequel vous avez besoin de méthodes de retour de référence, je voudrais aimer pour entendre parler de il. Plus nous avons de scénarios réels, plus il est probable qu'une telle fonctionnalité puisse être implémentée dans une future version hypothétique du langage.

Voir également les questions connexes:

Puis-je utiliser une référence à l'intérieur d'une fonction C # comme C++?

Pourquoi C # ne prend-il pas en charge le retour des références?

et mon blog sur le sujet:

http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/

43
Eric Lippert

Non, ce n'est pas possible en C #. Vous ne pouvez transmettre des paramètres que par référence.

Cependant, vous pouvez obtenir le même résultat avec une propriété:

double Element
{
    get { return doubleArray[x,y,z]; }
    set { doubleArray[x,y,z] = value; }
}

void func()
{
   Element = 5.0;
}
8
Thomas Levesque

Vous pourriez le faire dans code non sûr et avoir une méthode qui retourne un pointeur à doubler:

unsafe double* GetElementP(){
...
}
6
Axarydax

Après réflexion, pourquoi ne pas envoyer la valeur à définir avec la fonction comme ceci:

void SetElement(double value)
{
   ......
   // Calculate x,y,z
   doubleArray[x,y,z]=value;
}

et l'utiliser:

void func()
{
   SetElement(5.0);
}

Cependant, je choisirai toujours l'une de vos réponses utiles ...

1
Betamoo