Logo

¡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.
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.