Jump to content
Tizon

Interfaces y listas

Recommended Posts

A ver si alguien me da una idea por qué no doy con ello. Aunque no he apretado mucho con la teórica de C#, doy por supuesto que se puede crear una lista de interfaces, dado que lo he conseguido en un caso simple, pero no en el segundo doble, a mi parecer idénticos excepto por eso, de ahí mi perplejidad. Aclarar, que he aprendido C# a base de leches, así que a no descartar que se me esté yendo.

Bien, al lío. Necesito crear tipos diferentes de Interfaces y tipos diferentes de datos con una o más interfaces, que para eso están, no? O al menos eso creo. Por otro lado deseo guardar listas de los objetos creados con cada uno de las interfaces, por lo que he decido crear un singleton. Bien para hacernos una idea, simplifico al máximo.

public class UnoParaGuardarlosATodos : Monobehavior {

     public static UnoParaGuardarlosATodos miSharedInstance;

     public List<IMiInterfaceA> misObjetosConInterfaceA = new List<IMiInterfaceA>();

     public List<IMiInterfaceB> misObjetosConnIterfaceB = new List<IMiInterfaceB>();

     public void f_InstanciaObjetosConInterface(){

          ObjetoTipoA miObjetoTipoA = new ObjetoTipoA();

          ObjetoTipoB miObjetoTipoB = new ObjetoTipoB();

     }

}

Bien, único objeto que tira de Monobehavior. Luego creo dos Interfaces.

public interface IMiInterfaceA {

     void f_Iregistra();

     funcion1();

     funcion2();

     funcionN();

}

y

public interface IMiInterfaceB {

     void f_Iregistra();

     funcion1();

     funcion2();

     funcionN();

}

Y dos objetos.

public class ObjetoTipoA : IMiInterfaceA {

     public ObjetoTipoA() {

          f_Iregistra()

     }

     public void f_Iregistra() {

          UnoParaGuardarlosATodos.miSharedInstance.misObjetosConInterfaceA.add(this);

     }

}

Este primero se lo traga sin problema. No tira error. Creo el segundo.

public class ObjetoTipoB : IMiInterfaceA, IMiInterfaceB {

     public ObjetoTipoB() {

          f_Iregistra()

     }

     public void f_Iregistra() {

          UnoParaGuardarlosATodos.miSharedInstance.misObjetosConInterfaceA.add(this);

          UnoParaGuardarlosATodos.miSharedInstance.misObjetosConInterfaceB.add(this);

     }

}

Con este segundo si me tira error. Para ser más concreto, este: 

Cita

NullReferenceException: Object reference not set to an instance of an object
Tzn.ObjetoTipoB.f_Iregistra () (at Assets/Scripts/Programa/ObjetoTipoB.cs:31)
Tzn.ObjetoTipoB..ctor () (at Assets/Scripts/Programa/ObjetoTipoB.cs:21)

El error me lo tira primero en la función f_Iregistra y después en el constructor. El problema es que me lo tira directamente en el editor, con lo que no puedo debuggearlo, y el único modo de saber que narices le pasa es comentando líneas. Así he llegado a lo que le molesta, que es cualquiera de las dos líneas:

Cita

 

          UnoParaGuardarlosATodos.miSharedInstance.misObjetosConInterfaceA.add(this);

          UnoParaGuardarlosATodos.miSharedInstance.misObjetosConInterfaceB.add(this);

 

Lo curioso es que he copiado y pegado la línea de la clase ObjetoTipoA, por si fuera un error de sintaxis, nada. No puede ser el Singleton, dado que es ese el que crea los objetos de las clases. Mi duda es si al tener dos interfaces con la misma función, pero todo lo que leo (A menos que lo interprete al revés, cosa a no descartar, soy medio así... ) no sólo es que se pueda, sino que es como se DEBE de hacer, para hacer código legible, mantenible y blabla... Pero el caso es que si hago que implemente sólo una de las dos Interfaces (Sea cual sea, la A o la B) si me funciona...

Llegados a este punto, ya no sé por dónde tirar...

Acepto ideas, sugerencias y tirones de pelo.

Muchas gracias a todos.

Edited by pioj
Por favor, usa el <> o el "quote" para pegar código.

Share this post


Link to post
Share on other sites
hace 6 minutos, Tizon said:

public void f_Iregistra() {

          UnoParaGuardarlosATodos.miSharedInstance.misObjetosConInterfaceA.add(this);

          UnoParaGuardarlosATodos.miSharedInstance.misObjetosConInterfaceB.add(this);

     }

No me considero programador, pero aquí no estás añadiendo en el método de InterfaceB f_Iregistra(), a la lista del tipo InterfaceB un objeto de InterfaceA?

Share this post


Link to post
Share on other sites
hace 18 minutos, FluXarTStudios said:

No me considero programador, pero aquí no estás añadiendo en el método de InterfaceB f_Iregistra(), a la lista del tipo InterfaceB un objeto de InterfaceA?

Entiendo que no. La Interface A y la B tienen la misma función (al final las interfaces no son más que un contrato) y mientras la función esté implementada es válida para las dos (O así lo he entendido) y el objeto B, al implementar la interface A y la B, y cumplir con ambos contratos, debiera (A no ser que me equivoque) poder añadirse a las listas de A y de B respectivamente, o al menos eso creo... A ver si alguien puede confirmar o sacarme del error... :)

Share this post


Link to post
Share on other sites

No ves algo raro en crear dos Interfaces con la misma función??

Aunque no creo que eso esté bien (crear dos interfaces con la misma función) prueba a implementar las interfaz de forma explícita:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation

public ClaseB : InterfaceA, InterfaceB {

void InterfaceA.Registrar ()
{
	RegistrarEnA();
}
void InterfaceB.Registrar ()
{
	RegistrarEnB();
}

}

 

Edited by juanma_teso

Share this post


Link to post
Share on other sites
hace 23 horas, juanma_teso said:

No ves algo raro en crear dos Interfaces con la misma función??

Aunque no creo que eso esté bien (crear dos interfaces con la misma función) prueba a implementar las interfaz de forma explícita:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation


public ClaseB : InterfaceA, InterfaceB {

void InterfaceA.Registrar ()
{
	RegistrarEnA();
}
void InterfaceB.Registrar ()
{
	RegistrarEnB();
}

}

 

Mañana pruebo a ver. Muchas gracias.

Share this post


Link to post
Share on other sites
On 23/7/2018 at 21:04, juanma_teso said:

No ves algo raro en crear dos Interfaces con la misma función??

Aunque no creo que eso esté bien (crear dos interfaces con la misma función) prueba a implementar las interfaz de forma explícita:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation


public ClaseB : InterfaceA, InterfaceB {

void InterfaceA.Registrar ()
{
	RegistrarEnA();
}
void InterfaceB.Registrar ()
{
	RegistrarEnB();
}

}

 

No, me sigue tirando el mismo error ya en edición, incluso he probado a separar los nombres de funciones, tipo RegistrarIbntefaceA y RegistrarInterfaceB para que no se llamen igual, y me sigue tirando el mismo error.

El error me da en la siguiente línea;

            TznConEscenariosController.miSharedInstance.misColoreaSegunPais.Add(this);

Me llama la atención que el List de Interfaces no me lo muestra en el Editor. Al principio lo atribuí a que a lo mejor en el inspector no muestra las Interfaces y objetos asociados en el Inspector. Pero como el fallo me dice que no encuentra el objeto (el objeto que posee la Interface debe de encontrarlo por narices, puesto que ejecuto desde el constructor, así que está recién salido del horno) empiezo a sospechar de la lista. La creo del siguiente modo, como he hecho siempre con todas las listas:

        public List<ITznColoreaSegúnPais> misColoreaSegunPais = new List<ITznColoreaSegúnPais>();

Lo único que se me ocurre ya a estas alturas, al menos como prueba es ejecutar en el constructor una corrutina y retrasar la llamada a la funcion registra de la interface, a ver si lo que falla es que el objeto aún se está construyendo... Aunque eso ya tendrá que esperar a mañana o pasado que tenga tiempo.

Mientras si cualquiera tiene cualquier ayuda o sugerencia, estaré muy agradecido, ya que si lo de la corrutina falla, ya no sé que hacer...

 

 

Share this post


Link to post
Share on other sites

Si utilizas la función Awake para las asignaciones y las funciones Start para los comportamientos de inicio jamas vas a tener errores de referencias nulas al trabajar con componentes compartidos.

Share this post


Link to post
Share on other sites

Nada, he puesto una corrutina para retrasar por si era problema del constructor, y ahora el error me salta en la corrutina. Es un poco desesperante esto...

hace 13 horas, juanma_teso said:

Fíjate si tienes asignado el singleton, de lo contrario no podrás acceder a tu objeto a través de él.

Si, esta asignado y correctamente, puesto que es el controlador de escenario, y se encarga de instanciar todos los componentes e instancia un montón sin novedad antes de eso, y los carga en otras listas de control que son visibles en el inspector, etc...

hace 12 horas, francoe1 said:

Si utilizas la función Awake para las asignaciones y las funciones Start para los comportamientos de inicio jamas vas a tener errores de referencias nulas al trabajar con componentes compartidos.

El caso es que una clase pura, no hereda de Monobehavior, con lo que no tiene disponibles ni Awake ni Start, pero lo haré así, a ver si así...

Muchas gracias a ambos por las ideas.

Share this post


Link to post
Share on other sites

Solo para ir probando cosas nuevas, deja las funciones de la interfaz vacías y agrega los objetos a la lista de otra forma:

On 23/7/2018 at 19:31, Tizon said:

 


public class UnoParaGuardarlosATodos : Monobehavior {

     public static UnoParaGuardarlosATodos miSharedInstance;

     public List<IMiInterfaceA> misObjetosConInterfaceA = new List<IMiInterfaceA>();

     public List<IMiInterfaceB> misObjetosConnIterfaceB = new List<IMiInterfaceB>();

     public void f_InstanciaObjetosConInterface(){

          ObjetoTipoA miObjetoTipoA = new ObjetoTipoA();

          ObjetoTipoB miObjetoTipoB = new ObjetoTipoB();
       
		misObjetosConnIterfaceB.Add((miObjetoB);

     }

}

 

Así sabremos si lo que falla es que la lista no está iniciada o la implementación de la interfaz.

Share this post


Link to post
Share on other sites
On 26/7/2018 at 21:14, juanma_teso said:

Solo para ir probando cosas nuevas, deja las funciones de la interfaz vacías y agrega los objetos a la lista de otra forma:

Así sabremos si lo que falla es que la lista no está iniciada o la implementación de la interfaz.

Pues manda narices, que saco el registro en las listas de las Interfaces, y no me tira error y me funciona aparentemente perfecto. He metido un Debug.Log para checar que realmente entra en las funciones vacías de registro de la Interface, y lo hace. Me genera los prefabs y todo perfecto. La única cosa curiosa es que en el inspector sigue sin mostrarme las listas de Interfaces, pero bueno, eso puede ser normal, es la primera vez que trabajo con listas de Interfaces, así que no sé...

Pero vamos, que me quedo con las ganas de conocer el origen del problema, si las interfaces o las listas, o el registro de las mismas. La combinación de todas, que curiosamente en otra clase si me va...

Así que me quedo sin saber el qué exactamente, y por lo tanto sin sacar conclusiones y sin aprender.

Share this post


Link to post
Share on other sites

Yo creo que sí sacamos varias cosas en claro, no son las listas y tampoco el hecho de que tenga las dos interfaces, el problema está en la implementación de las interfaces, prueba a registrar en cada lista con su función de interface:

public class ObjetoB : InterfaceA, InterfaceB
{
	public ObjetoB ()
	{
		InterfaceA.Registrar();
		InterfaceB.Registrar();
	}

	public void InterfaceA.Registrar ()
	{
		ListaA.Add();
	}

	public void InterfaceB.Registrar ()
	{
		ListaB.Add();
	}
}

No sé si así lo hiciste cuando te dije que implementaras de forma explícita las interfaces...

Share this post


Link to post
Share on other sites
1 hour ago, juanma_teso said:

Yo creo que sí sacamos varias cosas en claro, no son las listas y tampoco el hecho de que tenga las dos interfaces, el problema está en la implementación de las interfaces, prueba a registrar en cada lista con su función de interface:


public class ObjetoB : InterfaceA, InterfaceB
{
	public ObjetoB ()
	{
		InterfaceA.Registrar();
		InterfaceB.Registrar();
	}

	public void InterfaceA.Registrar ()
	{
		ListaA.Add();
	}

	public void InterfaceB.Registrar ()
	{
		ListaB.Add();
	}
}

No sé si así lo hiciste cuando te dije que implementaras de forma explícita las interfaces...

Si, así lo hice en su momento...

Bueno, a ver como narices explico esto... Lo he vuelto ha hacer todo desde el inicio (Unas cuantas horillas), y me funciona todo a la perfección, incluido, tal como había leído, implementar en una única función las dos interfaces, es decir:

public void Registra(){

            ListaA.Add(this);

            ListaB.Add(this);

}

Y no me da error en ninguno de las dos Interfaces. Por qué? No me lo explico.Supongo que en algún lugar cometí algún error estúpido que no he sabido ver (Si, soy propenso a ello...). El caso es que normalmente cuando consigo que funcione, digo, ah coña, pues era esto, o lo otro, o la lié en esto... En este caso, juraría que he hecho exactamente lo mismo que la primera vez que me tiró el error, y no caigo en que pudiera haberla liado. Bueno, el caso es que una semana perdida, vueltas por todos lados y vuelta al punto de inicio, esta funcionando, pero sin que sea capaz de encontrar la diferencia. Lo único bueno, es una serie de conclusiones que extraigo tras trabajar con Interfaces por primera vez a este nivel. Ojalá esto sirva también para los demás.

1,. Puedes declarar una misma función en dos o más interfaces diferentes, al implementar en la clase, lo puedes hacer en una única función, lo cual va estupendo para centralizar funcionalidades.

2.- Puedes al mismo tiempo implementar de forma explicita, si quieres que esta clase se comporte de modo diferente según que interface sea la que llame a la función, puede ir bien para muchas cosas.

3.- Las Interfaces puedes ir agregándolas a listas de la clase de la Interface, independientemente del objeto que la posea. Puede ir muy bien para hacer iteraciones secuenciales de todos los objetos que posean esta interface. Te ahorras ir buscando los objetos por tipos o demás. Los tienes todos agrupaditos en un sitio independiente del tipo que implemente. Entiendo que esto ocupa un poco más de memoria, pero seguro que es mucho más efectivo en tiempo de ejecución.

4.- Las listas de Interfaces (Salvo error u omisión) no se muestran en el inspector, cosa relativamente lógica, por los diferentes tipos que puede representar las clases que la implementen.

Bueno, dicho esto, dar mil gracias y pedir mil perdones a todos los que han participado en el hilo.

 

Edited by Tizon

Share this post


Link to post
Share on other sites

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...