Oleg Vazhnev
En mi aplicación de C#, recibo un puntero a una estructura de C++ en devolución de llamada/delegado. no estoy seguro si class
puede hacer el truco, pero solo lanzar un puntero de C++ a una estructura de C# adecuada funciona bien, así que estoy usando una estructura de C# para almacenar datos.
Ahora quiero pasar una referencia a la estructura para su posterior procesamiento.
- no puedo usar
class
porque probablemente no se “asignará” perfectamente a la estructura de C++. - No quiero copiar la estructura para una mejor latencia.
¿Cómo puedo hacer eso?
Este ejemplo demuestra que struct se pasa por valor, no por referencia:
using System;
namespace TestStruct
{
struct s
{
public int a;
}
class Program
{
static void Main(string[] args)
{
s s1 = new s
{
a = 1
};
Foo(s1);
Console.WriteLine("outer a = " + s1.a);
}
private static void Foo(s s1)
{
s1.a++;
Console.WriteLine("inner a = " + s1.a);
}
}
}
La salida es:
inner a = 2
outer a = 1
Parece que solo quieres usar ref
para pasar la estructura por referencia:
private static void Foo(ref s s1)
{
s1.a++;
Console.WriteLine("inner a = " + s1.a);
}
Y en el sitio de la llamada:
Foo(ref s1);
Mira mi artículo sobre el paso de parámetros en C# para más detalles.
Tenga en cuenta que, aparte de la interoperabilidad, normalmente recomendaría encarecidamente contra usando estructuras mutables como esta. Sin embargo, puedo entender los beneficios aquí.
-
+1. Nota al margen: manejo de código
struct
debe escribirse con mucho cuidado ya que casi todas las operaciones construct
crear una copia (excepto matriz, donde aún puede tomar unaref
de un elemento).– Alexéi Levenkov
17 mayo 2013 a las 17:25
-
¿Por qué recomienda encarecidamente no pasar estructuras por
ref
? Por lo que puedo decir, es lo mismo que pasar por referencia en C++ (p.std::string&
), y puede eliminar la copia innecesaria de estructuras potencialmente grandes.– Colin Basnett
21 de junio de 2015 a las 21:05
-
@cmbasnett: Recomiendo enfáticamente no usar estructuras mutables. Pasar una estructura por ref está bien, pero a) desaconsejaría estructuras grandes en general; b) Yo argumentaría en contra mudable structs (al igual que las pautas de diseño de Microsoft) ya que pueden causar una serie de sorpresas.
– Jon Skeet
21 de junio de 2015 a las 21:20
lorenzo delana
Puedes usar c# 7.2 in
palabra clave de la siguiente manera:
static float Sample(in Vector3 v)
{
// v.X = 2; // <-- this generate follow compiler error
// error CS8332: Cannot assign to a member of variable 'v'
// or use it as the right hand side of a ref assignment
// because it is a readonly variable
return v.X;
}
Esto asegura que el argumento de la estructura v sea:
- solo lectura
- pasado por árbitro
detalles de IL
Vector3 v = Vector3.One;
float Sample(Vector3 v)
{
return v.X;
}
System.Console.WriteLine(Sample(v));
float ReadonlySample(in Vector3 v)
{
return v.X;
}
System.Console.WriteLine(ReadonlySample(v));
producir seguir IL:
// Vector3 v2 = Vector3.One;
IL_0001: call valuetype [System.Numerics.Vectors]System.Numerics.Vector3 [System.Numerics.Vectors]System.Numerics.Vector3::get_One()
IL_0006: stloc.0
// Console.WriteLine(Sample(v2));
IL_0007: nop
IL_0008: ldloc.0
IL_0009: call float32 test_console.Sample::'<Main>g__Sample|0_0'(valuetype [System.Numerics.Vectors]System.Numerics.Vector3)
IL_000e: call void [System.Console]System.Console::WriteLine(float32)
// (no C# code)
IL_0013: nop
// Console.WriteLine(ReadonlySample(in v2));
IL_0014: nop
IL_0015: ldloca.s 0
IL_0017: call float32 test_console.Sample::'<Main>g__ReadonlySample|0_1'(valuetype [System.Numerics.Vectors]System.Numerics.Vector3&)
IL_001c: call void [System.Console]System.Console::WriteLine(float32)
puedes ver que usando in
tenemos ldloca en lugar de ldloc.
En resumen, la estructura se pasa como si fuera un ref
pero está protegido contra escrituras por el compilador gracias a la in
.
-
Cuando escribo el post me faltó insertar este referencia ; puede probarlo usted mismo simplemente cambiando la versión de idioma en csproj, por ejemplo, configurando
<LangVersion>6</LangVersion>
producirá el siguiente error para el mismo código anteriorerror CS8059: Feature 'readonly references' is not available in C# 6. Please use language version 7.2 or greater.
– Lorenzo Delana
8 de marzo a las 8:18
Tenga cuidado con su razonamiento sobre la estructura:
struct
en C++ es exactamente igual que la clase (salvo la accesibilidad predeterminada), mientras que en C# son completamente diferentes: tipos de valor y referencia. Lo más probable es que realmente sea mejor con las clases en C#; al menos, lea y comprenda cómostruct
comportarse en C#.– Alexéi Levenkov
17 mayo 2013 a las 17:27
Una gran cantidad de mis clases de interoperabilidad son de hecho clases y no estructuras. Si configura la clasificación correctamente (y, a menudo, la clasificación predeterminada funciona), entonces puede usar una clase. En caso de duda, primero pruebo con una clase.
–Matthew Watson
17 mayo 2013 a las 17:47
Las estructuras mutables son malas.
– John Alexiou
8 de marzo a las 0:17