Considérez le code suivant:
private unsafe void Function()
{
int length;
// This line raises error CS1686, "Local 'length' or its members cannot have their address taken and be used inside an anonymous method or lambda expression".
glGetProgramiv(1, GL_PROGRAM_BINARY_LENGTH, &length);
FunctionWithLambda(() => Console.WriteLine(length));
}
private void FunctionWithLambda(Action callback)
{
callback();
}
Notez que je prends l'adresse de length
(une variable locale), puis utilisez la variable la variable elle-même ( non Son adresse) une lambda. Je comprends pourquoi une adresse de variable locale ne peut pas être utilisée dans une lambda directement (voir pourquoi ne pouvez-je pas passer l'adresse d'une variable à une fonction anonyme? , parmi Autres exemples), mais pourquoi ne puis-je pas utiliser le valeur de length
une fois attribué (même si cette affectation arrive à utiliser le &
opérateur)? La documentation officielle pour erreur CS1686 ( https://docs.microsoft.com/bs-latn-ba/dotnet/cshaarp/misc/cs1686 ) n'a pas clarifié cette confusion.
Mon hypothèse est que c'est simplement une limitation de la langue, mais je suis curieux s'il y a une raison technique sous-jacente, je manque. Notez également que je ne demande pas Comment travailler autour de ce problème (Je sais que je peux facilement copier length
à une autre variable locale en premier).
Je suppose que la raison est simple: trop complexe à compiler.
Il y a 2 problèmes que le compilateur doit résoudre:
Supposons que les codes suivants sont valides.
unsafe void Function()
{
int length = 1;
void bar() => Console.WriteLine(length);
bar();
foo(&length);
bar();
}
unsafe void foo(int* i) { (*i)++; }
Le résultat attendu est:
1
2
Pour résoudre le premier problème, c # générera une classe anonyme pour tenir la suppression.
Voici le pseudocode:
class _Anonymous
{
public int _length;
public void _bar() { Console.WriteLine(_length); }
}
unsafe void Function()
{
int length = 1;
var a = new _Anonymous { _length = length };
a._bar();
foo(&length);
a._bar();
}
Pour résoudre le deuxième problème C # utilise le champ généré au lieu de la variable locale d'origine.
unsafe void Function()
{
//int length = 1;
var a = new _Anonymous { _length = 1 };
a._bar();
foo(&a._length);
a._bar();
}
Ce sont toutes les œuvres qu'un compilateur peut faire. Mais jusqu'à présent, les codes ne fonctionneront toujours pas, nous avons besoin d'un bloc fixe supplémentaire.
unsafe void Function()
{
var a = new _Anonymous { _length = 1 };
a._bar();
fixed (int* p = &a._length)
foo(p);
a._bar();
}
La limitation peut donc être enlevée avec un compilateur plus intelligent, mais les choses sont plus faciles si nous interdisons ce type de codes.