Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Duda de C# y genericos

Iniciado por blau, 30 de Septiembre de 2011, 09:57:44 PM

« anterior - próximo »

blau

Estoy definiendo las estructuras que almacenan los datos usados para interpolar valores...

he usado genéricos por reusar código y mantener una misma lógica para todo... pero como no me resuelve el tipo genérico hasta que lo decalro, tengo que copiar el mismo codigo una y otra vez en las clases finales...

Ver InterpolatorDataColor, InterpolatorDataVector2, InterpolatorDataFloat, ... los metodos LoadKey y SaveKey son identicos...

la pregunta clave es ¿Hay alguna manera sencilla de subir estos dos métodos a la clase padre genérica?


Bueno ahí va un tocho de código...

Código (csharp) [Seleccionar]

namespace Engine.Interpolators
{
   public enum InterpolatorDataTypes { Float, Color, Vector2 }
   public enum InterpolationTypes { None, Linear, Bezier, Hermite }

   //------------------------------------------------------------------------------------------------------------
   public class KeyData<T>  where T : struct
   {
       public float Time;
       public T Value;
       public T InTan;
       public T OutTan;
   }

   //------------------------------------------------------------------------------------------------------------
   public abstract class InterpolatorData : Engine.Core.Data
   {
       public abstract InterpolatorDataTypes InterpolatorDataType { get; }
       public InterpolationTypes InterpolationType;

       protected override void OnSave( XmlWriter writer )
       {
           writer.WriteElementString( "InterpolationType", InterpolationType.ToString() );
       }

       protected override void OnLoad( XmlReader reader )
       {
           InterpolationType = (InterpolationTypes) Enum.Parse( typeof(InterpolationTypes), reader.ReadElementString( "InterpolationType" ) );
       }
   }

   //------------------------------------------------------------------------------------------------------------
   public abstract class InterpolatorData<T> : InterpolatorData where T : struct
   {
       public List<KeyData<T>> Keys = new List<KeyData<T>>( );

       protected override void OnSave( XmlWriter writer )
       {
           base.OnSave( writer );
           writer.WriteStartElement( "Keys" );
           writer.WriteAttributeString( "Count", Keys.Count.ToString( CultureInfo.InvariantCulture ) );
           {
               for ( int index = 0; index < Keys.Count; index++ )
                   SaveKey( index, writer );
           }
           writer.WriteEndElement( );
       }

       protected override void OnLoad( XmlReader reader )
       {
           int Count;
           base.OnLoad( reader );
           reader.ReadToFollowing( "Keys" );
           reader.GetAttribute( "Count", out Count );
           reader.ReadStartElement( "Keys" );
           Keys = new KeyData<T>[ Count ].ToList();
           for ( int index=0; index < Count; index++ )
           {
               Keys[index] = new KeyData<T>( );
               LoadKey( index, reader );
           }
       }

       protected abstract void SaveKey( int index, XmlWriter writer );
       protected abstract void LoadKey( int index, XmlReader reader );  
   }

   //------------------------------------------------------------------------------------------------------------
   public class InterpolatorDataColor : InterpolatorData<Microsoft.Xna.Framework.Color>
   {
       public override InterpolatorDataTypes InterpolatorDataType { get { return InterpolatorDataTypes.Color; } }

       protected override void SaveKey(int index, XmlWriter writer)
       {
           writer.WriteStartElement( "Key" );
           {
               writer.WriteElementString( "Time", Keys[index].Time );
               writer.WriteElementString( "Value", Keys[index].Value );
               if ( InterpolationType == InterpolationTypes.Bezier || InterpolationType == InterpolationTypes.Hermite )
               {
                   writer.WriteElementString( "InTan", Keys[index].InTan );
                   writer.WriteElementString( "OutTan", Keys[index].OutTan );
               }
           }
           writer.WriteEndElement( );
       }

       protected override void LoadKey( int index, XmlReader reader )
       {
           reader.ReadStartElement( "Key" );
           {
               reader.ReadElementString( "Time", out Keys[index].Time );
               reader.ReadElementString( "Value", out Keys[index].Value );
               if ( InterpolationType == InterpolationTypes.Bezier || InterpolationType == InterpolationTypes.Hermite )
               {
                   reader.ReadElementString( "InTan", out Keys[index].InTan );
                   reader.ReadElementString( "OutTan", out Keys[index].OutTan );
               }
           }
           reader.ReadEndElement( );
       }
   }

   //------------------------------------------------------------------------------------------------------------
   public class InterpolatorDataFloat : InterpolatorData<Single>
   {
       public override InterpolatorDataTypes InterpolatorDataType { get { return InterpolatorDataTypes.Float; } }

       protected override void SaveKey( int index, XmlWriter writer )
       {
           writer.WriteStartElement( "Key" );
           {
               writer.WriteElementString( "Time", Keys[index].Time );
               writer.WriteElementString( "Value", Keys[index].Value );
               if ( InterpolationType == InterpolationTypes.Bezier || InterpolationType == InterpolationTypes.Hermite )
               {
                   writer.WriteElementString( "InTan", Keys[index].InTan );
                   writer.WriteElementString( "OutTan", Keys[index].OutTan );
               }
           }
           writer.WriteEndElement( );
       }
       protected override void LoadKey( int index, XmlReader reader )
       {
           reader.ReadStartElement( "Key" );
           {
               reader.ReadElementString( "Time", out Keys[index].Time );
               reader.ReadElementString( "Value", out Keys[index].Value );
               if ( InterpolationType == InterpolationTypes.Bezier || InterpolationType == InterpolationTypes.Hermite )
               {
                   reader.ReadElementString( "InTan", out Keys[index].InTan );
                   reader.ReadElementString( "OutTan", out Keys[index].OutTan );
               }
           }
           reader.ReadEndElement( );
       }  
   }

   //------------------------------------------------------------------------------------------------------------
   public class InterpolatorDataVector2 : InterpolatorData<Microsoft.Xna.Framework.Vector2>
   {
       public override InterpolatorDataTypes InterpolatorDataType { get { return InterpolatorDataTypes.Vector2; } }

       protected override void SaveKey( int index, XmlWriter writer )
       {
           writer.WriteStartElement( "Key" );
           {
               writer.WriteElementString( "Time", Keys[index].Time );
               writer.WriteElementString( "Value", Keys[index].Value );
               if ( InterpolationType == InterpolationTypes.Bezier || InterpolationType == InterpolationTypes.Hermite )
               {
                   writer.WriteElementString( "InTan", Keys[index].InTan );
                   writer.WriteElementString( "OutTan", Keys[index].OutTan );
               }
           }
           writer.WriteEndElement( );
       }

       protected override void LoadKey( int index, XmlReader reader )
       {
           reader.ReadStartElement( "Key" );
           {
               reader.ReadElementString( "Time", out Keys[index].Time );
               reader.ReadElementString( "Value", out Keys[index].Value );
               if ( InterpolationType == InterpolationTypes.Bezier || InterpolationType == InterpolationTypes.Hermite )
               {
                   reader.ReadElementString( "InTan", out Keys[index].InTan );
                   reader.ReadElementString( "OutTan", out Keys[index].OutTan );
               }
           }
           reader.ReadEndElement( );
       }  
   }
}



Un saludo

Vicente

Desgraciadamente para poderlo hacer generico el WriteElementString y el ReadElementString tendrian que soportar genericos.

Pero podrias hacer un poco de trampa lo mismo para el Write, en vez de:

writer.WriteElementString( "Value", Keys[index].Value );

Hacer:

writer.WriteElementString( "Value", Keys[index].Value.ToString() );

Tienes el constraint a Struct y las Struct tienen el metodo ToString(), asi que deberia colar...

Para el Read no se me ocurre nada :(

blau

De hecho hago trampas.... :)

estoy usando extensiones del xmlreader y del xmlwriter...


Código (csharp) [Seleccionar]

public static class XmlExtension
    {
        public static void WriteElementString( this XmlWriter writer, string element, Color value )
        {
            writer.WriteElementString(
                element,
                value.R.ToString( CultureInfo.InvariantCulture ) + ',' +
                value.G.ToString( CultureInfo.InvariantCulture ) + ',' +
                value.B.ToString( CultureInfo.InvariantCulture ) + ',' +
                value.A.ToString( CultureInfo.InvariantCulture ) );
        }

        public static void WriteElementString( this XmlWriter writer, string element, Vector2 value )
        {
            writer.WriteElementString( element, value.X.ToString( CultureInfo.InvariantCulture ) + ',' + value.Y.ToString( CultureInfo.InvariantCulture ) );
        }

        public static void WriteElementString( this XmlWriter writer, string element, int value )
        {
            writer.WriteElementString( element, value.ToString( CultureInfo.InvariantCulture ) );
        }

        public static void WriteElementString( this XmlWriter writer, string element, float value )
        {
            writer.WriteElementString( element, value.ToString( CultureInfo.InvariantCulture ) );
        }


        public static void ReadElementString( this XmlReader reader, string element, out Color value )
        {
            string data = reader.ReadElementString( element );

            byte[] values = data.Split( ',' ).Select<string, byte>( s => byte.Parse( s, CultureInfo.InvariantCulture ) ).ToArray( );
            value = new Color( values[0], values[1], values[2], values[3] );
        }

        public static void ReadElementString( this XmlReader reader, string element, out Vector2 value )
        {
            string data = reader.ReadElementString( element );

            float[] values = data.Split( ',' ).Select<string, float>( s => float.Parse( s, CultureInfo.InvariantCulture ) ).ToArray( );
            value.X = values[0];
            value.Y = values[1];
        }

        public static void ReadElementString( this XmlReader reader, string element, out int value )
        {
            string s = reader.ReadElementString( element );
            value = int.Parse( s, CultureInfo.InvariantCulture );
        }

        public static void ReadElementString( this XmlReader reader, string element, out float value )
        {
            string s = reader.ReadElementString( element );
            value = float.Parse( s, CultureInfo.InvariantCulture );
        }

        public static void GetAttribute( this XmlReader reader, string attribute, out int value )
        {
            string data = reader.GetAttribute( attribute );
            value = int.Parse( data, CultureInfo.InvariantCulture );
        }
    }
}


El tema es que podria hacer metodos genericos tambien... pero no se por que no me han gustado mucho, seria algo asi:

public static void ReadElementString<T>( this XmlReader reader, string element, out T value  ) where T:struct, new()
        {
              if (T is Color) {
                  Color c;
                  ReadElementString(reader, element, out c);
                   value = (T)(object)c;
               }
              else ....
        }

Si no recuerdo mal se hacia asi... ¿hay alguna otra idea?

blau

Al final no se ha quedado feo del todo, lo he hecho asi:


        public static void ReadElementString<T>( this XmlReader reader, string element, out T value ) where T : struct
        {
            string Data = reader.ReadElementString( element );

            Type type = typeof( T );

            if ( type == typeof( Color ) ) value = (T) (object) StringToColor( Data );
            else if ( type == typeof( Vector2 ) ) value = ( T ) ( object ) StringToVector2( Data );
            else if ( type == typeof( int ) ) value = ( T ) ( object ) StringToInt( Data );
            else if ( type == typeof( float ) ) value = ( T ) ( object ) StringToFloat( Data );
            else throw new NotSupportedException( );
        }

        public static void WriteElementString<T>( this XmlWriter writer, string element, T value ) where T:struct
        {
            Type type = typeof( T );

            if ( type == typeof( Color ) ) WriteElementString( writer, element, ( Color ) ( object ) value );
            else if ( type == typeof( Vector2 ) ) WriteElementString( writer, element, ( Vector2 ) ( object ) value );
            else if ( type == typeof( int ) ) WriteElementString( writer, element, ( int ) ( object ) value );
            else if ( type == typeof( float ) ) WriteElementString( writer, element, ( float ) ( object ) value );
            else throw new NotSupportedException( );
        }

public class KeyData<T>  where T : struct
    {
        public float Time;
        public T Value;
        public T InTan;
        public T OutTan;

        public void Save(XmlWriter writer, bool FullSave)
        {
            writer.WriteStartElement( "Key" );
            {
                writer.WriteElementString( "Time", Time );
                writer.WriteElementString<T>( "Value", Value );
                if ( FullSave )
                {
                    writer.WriteElementString( "InTan", InTan );
                    writer.WriteElementString( "OutTan", OutTan );
                }
            }
            writer.WriteEndElement( );
        }

        public void Load( XmlReader reader, bool FullLoad)
        {
            reader.ReadStartElement( "Key" );
            {
                reader.ReadElementString( "Time", out Time );
                reader.ReadElementString<T>( "Value", out Value );
                if ( FullLoad )
                {
                    reader.ReadElementString<T>( "InTan",  out InTan );
                    reader.ReadElementString<T>( "OutTan", out OutTan );
                }
            }
            reader.ReadEndElement( );
        }







Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.