Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Listas En C#

Iniciado por Haddd, 15 de Septiembre de 2004, 10:09:02 AM

« anterior - próximo »

Haddd

 Quiero hacer una lista de fuentes en C#. Quiero poder utilizarla de esta forma:

Por índice: Fuentes(0)
Por nombre: Fuentes("Arial",8)

¿Cómo tengo que hacerlo en C#? El ejemplo de DX utiliza Hashtable, pero yo no necesito llegar a tanto.

Zaelsius

 Mira en System.Collections, y píllate un libro de C# , o al menos tutoriales, porque hay muchas clases del framework que no se parecen en nada a lo que tenemos en C++(ni en nombre ni en funcionamiento).

Grugnorr

 System.Collections
System.Collections.Generic <---en framework 2.0 hay generics->templates

Usa la clase ArrayList.

En C# existen los "indexer", básicamente el operator[] de C++ con sintaxis de Property.


public Font this[int posicion]
{
        get
       {
                  return listaInterna[posicion];
       }

        set
        {
                listaInterna[posicion] = value;
        }
}


Echale un ojo a IComparable también.

ListDictionary es un diccionario "ligero" :
Implements IDictionary using a singly linked list. Recommended for collections that typically contain 10 items or less

Está en System.Collections.Specialized

Cuando llegue a casa te podré dedicar algo más de tiempo, en general busca las cosas por el SDK del Framework o directamente con el Intellisense  (ole)  
hat the hells!

Haddd

 Mi idea es tener una clase genérica:


   public struct slistaNombres
   {
       public string nombre;
       public Object objeto;
   }

   public class ListaNombres
   {
       public ArrayList lista;
       //public slistaNombres[] lista;
       int numElementos=0;

       public Object this[int indice]
       {
           get { slistaNombres s=(slistaNombres)lista[indice];
               return s.objeto; }
       }
       public Object this[string nombre]
       {
           get {
               int l = numElementos, c;
               for (c = 0; c < l; c++)
               {
                   slistaNombres s = (slistaNombres)lista[c];
                   if ( string.Compare(s.nombre,nombre,true)==0)
                   {
                       return s.objeto;
                   }
               }
               return null;
           }
       }

       public ListaNombres()
       {
          lista = new ArrayList();
       }

       public void Insertar(string nombre,Object objeto)
       {
           int i = numElementos;

           slistaNombres s=new slistaNombres();

           s.nombre = nombre;
           s.objeto = objeto;

           lista.Add(s);
           
           numElementos++;
       }

       public bool Existe(string nombre)
       {
           return this[nombre] != null;
       }

       public Object Buscar(string nombre)
       {
           return this[nombre];

       }
   }


Y aquí su utilización:


       public class CFuentes : ListaNombres
       {
           Video video;
           Font textFont;  // fuente activa
           private Sprite textSprite; // Used to cache the drawn text

           public CFuentes(Video padre)
           {
               video = padre;
               // Create a sprite to help batch calls when drawing many lines of text
               textSprite = new Sprite(video.Device());
               // Creamos una fuente por defecto
               Insertar(24, 0, FontWeight.Bold, 1, false, CharacterSet.Default,
                   Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch
                   , "Arial");
           }
           /// <summary>
           /// Liberamos la memoria de la clase. Esto debe hacerse siempre antes de salir
           /// de la aplicación, puesto que no podemos controlar nunca si la aplicación ha eliminado
           /// el device
           /// </summary>
           public void Finalizar()
           {

               foreach(Object o in lista)
               {
                   slistaNombres s=(slistaNombres)o;
                   Font f=(Font)s.objeto;
                   f.Dispose();

               }
               textSprite.Dispose();
               textFont = null;

           }

           public Font Insertar(int height, int width, FontWeight weight, int mip, bool italic,
                               CharacterSet charSet, Precision outputPrecision, FontQuality quality, PitchAndFamily pandf, string fontName)
           {
               // Create the font description
               FontDescription desc = new FontDescription();
               desc.Height = height;
               desc.Width = width;
               desc.Weight = weight;
               desc.MipLevels = mip;
               desc.IsItalic = italic;
               desc.CharSet = charSet;
               desc.OutputPrecision = outputPrecision;
               desc.Quality = quality;
               desc.PitchAndFamily = pandf;
               desc.FaceName = fontName;

               return CreateFont(desc);
           }

           public Font CreateFont(FontDescription desc)
           {
               Font f = (Font)Buscar(desc.FaceName);

               if (f == null)
               {

                   f = new Font(video.Device(), desc);

                   if (f == null)
                   {
                       throw new InvalidOperationException("No he podido crear la fuente " + desc.FaceName);
                   }
                   // Insertamos en la lista
                   Insertar(desc.FaceName, f);
               }
               return f;
           }



Tengo colecciones típicas: Mallas, Fuentes, Texturas,... donde se repite el mismo patrón:

Insertar un elemento, comprobando si existe.

Acceder fácilmente a los miembros, buscando por nombre o por índice.
Eliminar la lista destruyendo los elementos.


Grugnorr

 Uhmm, ideas al vuelo:

public struct slistaNombres
  {
      public string nombre;
      public Object objeto;
  }


Insertas esa struct, que es un value type en un ArrayList, que guarda objects:
       
             a) Al ser un tipo valor, debe ser..."boxeado" (creado un object temporal que lo contenga) cada vez que lo insertes (cada vez que lo trates como una referencia(object) y "unboxed" al ser extraido. En Java se usan los Wrapper para ésto, aquí se encarga el clr. Repasa lo que es un struct en C#, debe ser lo que más ha cambiado respecto a C++. Los structs con una optimización de clases para casos concretos... y empeoran cuando los usas mal, como aquí -> cámbialo de struct a class, sin miedo  :P


             B) Si vas a darle el uso de tabla hash ligera, tienes las clases :
                         1) SortedList is a hybrid between a Hashtable and an Array. When an element is accessed by its key using the Item indexer property, it behaves like a Hashtable. When an element is accessed by its index using GetByIndex or SetByIndex, it behaves like an Array (inserciones que deben ordenar la lista de claves, pero más eficiente de recuperar valores al ser búsqueda binaria(logarítmica)
                         2) HybridDictionary Implements IDictionary by using a ListDictionary while the collection is small, and then switching to a Hashtable when the collection gets large.
                         3)ListDictionary Implements IDictionary using a singly linked list. Recommended for collections that typically contain 10 items or less
                          4) NameValueCollection Represents a sorted collection of associated String keys and String values that can be accessed either with the key or with the index.

                c) Si vas a usar el Framework2.0 como dijiste (deberías  (ole) ), mucho mejor que uses colecciones "templatizadas"

                d) ArrayList contiene la propiedad Count que indica el número de elementos (tal vez te lió que en los arrays es Length y en las Collections es Count?, piensa que Length es fijo y Count variable :) )


public void Insertar(string nombre,Object objeto)
      {
          int i = numElementos;

          slistaNombres s=new slistaNombres();

          s.nombre = nombre;
          s.objeto = objeto;

          lista.Add(s);
         
          numElementos++;
      }


Se te olvidó quitar eso, supongo int i = numElementos


Los métodos que expones no permiten modificar los elementos de la lista:


public Object Buscar(string nombre)
      {
          return this[nombre];

      }

  public Object this[string nombre]
      {
          get {
              int l = numElementos, c;
              for (c = 0; c < l; c++)
              {
                  slistaNombres s = (slistaNombres)lista[c];
                  if ( string.Compare(s.nombre,nombre,true)==0)
                  {
                      return s.objeto;
                  }
              }
              return null;
          }
      }


Volviendo al problema del boxing y el unboxing, si obtengo una referencia a un elemento de la lista  usando Buscar() o el indexer[string], en realidad recibiré una referencia a una copia, y los cambios que haga no se reflejarán en el elemento de la lista


El código de utilización, como veo que no compila no diré obviedades, aparte de cosas obvias:

      a) Porqué Finalizar() y no Dispose()  :blink:
      B) Cada clase que tenga recursos no manejados debería implementar además de Dispose() un Destructor. Sólo las que tengan recursos no manejados, los destructores son el otro gran cambio junto a las structs :)


PD: Lo siento, pero no me apetece leer lo que he escrito, espero no haber sonado pedante ni nada, ha sido un buen ejercicio de errores comunes y demás

PD2: Curiosidades del CLR:

int longitud = array.Length;
for (int i = 0;i{
//blah blah
}

es menos óptimo que:

for (int i = 0;i{
//blah blah
}

Ya que el Jitter es muy listo en general, y tiene una optimación que en el caso segundo sabe que es imposible que te salgas de límites en el array y elimina la comprobación de límites en el array  (ole)


PD3: Puedo meter la pata en algo, cualquier duda se piensa, ando con la cabeza fatal... a ver si llega el Martes de una vez  (nooo)  
hat the hells!

seryu

 si fuese listo de verdad entonces se daria cuenta como hacemos nosotros de qe es lo mismo  :P  

Grugnorr

 Tendría que verificar que la variable donde cacheas la longitud no ha sido modificada ni ha quedado obsoleta por haber hecho alguna otra operación sobre el array...vamos, hacer la comparación de límites ;)

Ya va mejorando poco a poco en esos casos, en otros piensa que al compilarse al ejecutar ya sabe que procesador tienes, creándote una versión lo más optimizada posible(pentium4+sse etc por ejemplo)
hat the hells!






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.