¿Cuál es el beneficio de usar / ref en lugar de regresar?
Estoy haciendo un juego usando el framework XNA, así que uso muchas funciones que operan en vectores. (especialmenteVector2 (64bit struct)). Lo que me molesta es que la mayoría de los métodos están definidos con parámetros de referencia y de salida. Aquí hay un ejemplo:
<code>void Min(ref Vector2 value1, ref Vector2 value2, out Vector2 result) </code>
lo que también me parece un poco extraño. También hay otroMin
que es mas obvio
<code>public static Vector2 Min(Vector2 value1, Vector2 value2); </code>
Básicamente, casi todas las funciones tienen sobrecargas conref
s yout
s. Similares, otrosAPIs.
¿Cuál es el beneficio de este diseño? XNA está optimizado para el rendimiento, ¿podría ser un resultado? Por ejemplo, Quaternion requiere 128b donde pasa menos ref.
EDITAR:
Aquí hay un código de prueba:
<code>public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; private Vector2 vec1 = new Vector2(1, 2); private Vector2 vec2 = new Vector2(2, 3); private Vector2 min; private string timeRefOut1; private string timeRefOut2; private SpriteFont font; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; refOut1(); refOut2(); } private Vector2 refOut1() { Vector2 min = Vector2.Min(vec1, vec2); return min; } private Vector2 refOut2() { Vector2.Min(ref vec1, ref vec2, out min); return min; } protected override void Initialize() { const int len = 100000000; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); for (int i = 0; i < len; i++) { refOut1(); } stopWatch.Stop(); timeRefOut1 = stopWatch.ElapsedMilliseconds.ToString(); stopWatch.Reset(); stopWatch.Start(); for (int i = 0; i < len; i++) { refOut2(); } stopWatch.Stop(); timeRefOut2 = stopWatch.ElapsedMilliseconds.ToString(); base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); font = Content.Load<SpriteFont>("SpriteFont1"); } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.DrawString(font, timeRefOut1, new Vector2(200, 200), Color.White); spriteBatch.DrawString(font, timeRefOut2, new Vector2(200, 300), Color.White); spriteBatch.End(); // TODO: Add your drawing code here base.Draw(gameTime); } } </code>
Los resultados:
refOut1 2200refOut2 1400Win 7 64bit, .Net 4. XNA 4.0
También el código IL
<code>.method public hidebysig static void Min(valuetype Microsoft.Xna.Framework.Vector2& value1, valuetype Microsoft.Xna.Framework.Vector2& value2, [out] valuetype Microsoft.Xna.Framework.Vector2& result) cil managed { // Code size 69 (0x45) .maxstack 3 IL_0000: ldarg.2 IL_0001: ldarg.0 IL_0002: ldfld float32 Microsoft.Xna.Framework.Vector2::X IL_0007: ldarg.1 IL_0008: ldfld float32 Microsoft.Xna.Framework.Vector2::X IL_000d: blt.s IL_0017 IL_000f: ldarg.1 IL_0010: ldfld float32 Microsoft.Xna.Framework.Vector2::X IL_0015: br.s IL_001d IL_0017: ldarg.0 IL_0018: ldfld float32 Microsoft.Xna.Framework.Vector2::X IL_001d: stfld float32 Microsoft.Xna.Framework.Vector2::X IL_0022: ldarg.2 IL_0023: ldarg.0 IL_0024: ldfld float32 Microsoft.Xna.Framework.Vector2::Y IL_0029: ldarg.1 IL_002a: ldfld float32 Microsoft.Xna.Framework.Vector2::Y IL_002f: blt.s IL_0039 IL_0031: ldarg.1 IL_0032: ldfld float32 Microsoft.Xna.Framework.Vector2::Y IL_0037: br.s IL_003f IL_0039: ldarg.0 IL_003a: ldfld float32 Microsoft.Xna.Framework.Vector2::Y IL_003f: stfld float32 Microsoft.Xna.Framework.Vector2::Y IL_0044: ret } // end of method Vector2::Min </code>
y
<code>.method public hidebysig static valuetype Microsoft.Xna.Framework.Vector2 Min(valuetype Microsoft.Xna.Framework.Vector2 value1, valuetype Microsoft.Xna.Framework.Vector2 value2) cil managed { // Code size 80 (0x50) .maxstack 3 .locals init (valuetype Microsoft.Xna.Framework.Vector2 V_0) IL_0000: ldloca.s V_0 IL_0002: ldarga.s value1 IL_0004: ldfld float32 Microsoft.Xna.Framework.Vector2::X IL_0009: ldarga.s value2 IL_000b: ldfld float32 Microsoft.Xna.Framework.Vector2::X IL_0010: blt.s IL_001b IL_0012: ldarga.s value2 IL_0014: ldfld float32 Microsoft.Xna.Framework.Vector2::X IL_0019: br.s IL_0022 IL_001b: ldarga.s value1 IL_001d: ldfld float32 Microsoft.Xna.Framework.Vector2::X IL_0022: stfld float32 Microsoft.Xna.Framework.Vector2::X IL_0027: ldloca.s V_0 IL_0029: ldarga.s value1 IL_002b: ldfld float32 Microsoft.Xna.Framework.Vector2::Y IL_0030: ldarga.s value2 IL_0032: ldfld float32 Microsoft.Xna.Framework.Vector2::Y IL_0037: blt.s IL_0042 IL_0039: ldarga.s value2 IL_003b: ldfld float32 Microsoft.Xna.Framework.Vector2::Y IL_0040: br.s IL_0049 IL_0042: ldarga.s value1 IL_0044: ldfld float32 Microsoft.Xna.Framework.Vector2::Y IL_0049: stfld float32 Microsoft.Xna.Framework.Vector2::Y IL_004e: ldloc.0 IL_004f: ret } // end of method Vector2::Min </code>
Parece que la sobrecarga es causada por el vector temp. También probé 1GHz WP 7.5 dispositivo:
19791677Número de tics para un orden de magnitud menor número de iteraciones.