Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Clases dinámicas en c#?

Iniciado por blau, 09 de Julio de 2012, 10:17:45 AM

« anterior - próximo »

blau

Quizás esté rizando el rizo... pero tengo el siguiente planteamiento...

   1. Brainiac Designer (gracias @Vicente ),       que es un gui open source para construir arboles de comportamiento,
            que tiene un sistema de plugins que permite importar los nodos con los que quieras trabajar.
            el problema es que los nodos tienen que derivar de su jerarquia de nodos que está orientada al diseño...
            además Brainiac accede a las propiedades del nodo y sus atributos por reflexión---


   2. TreeSharp... libreria open source que implementa la funcionalidad de los árboles de comportamiento... y donde tendré los nodos que quiero usar.


El problema, como no hay multiherencia en c# no puedo mezclarlos sin liar una gorda...

Por lo que me gustaría hacer un puente entre los dos de forma trasparente... la idea es desde el plugin cargar el ensamblado donde almaceno mis nodos derivados de treesharp... leer los tipos y crear tipos de derivados de brainiac de forma dinamica... para que el plugin se los pase al diseñador de brainiac y poder trabajar con ellos de forma totalmente automática...


Si quiero que las propiedades de un nodo treesharp se pasen al nuevo nodo brainiac tengo que crear tipos dinámicos, he planteado usar ExpandoObject pero hasta ahora no he logrado encontrar la forma en que derive de una clase de brainiac...  supongo que tendré que entrar al trapo en el código de brainiac y cambiar el modo de hacer las cosas... pero me da escalofríos....

alguien sabe como hacerlo o se le ocurre como hacer esto de cualquier otra forma?

PD: espero haberme explicado bien, que esta mañana me noto muy espeso  ^_^'

Vicente

No te vale algo asi como un wrapper? Te inventas una clase que hereda de las de Brainiac, que dentro tiene un nodo de TreeSharp, y que expone las propiedades del nodo de TreeSharp que te interesen.

O no he entendido muy bien el problema :S Un saludo!

Vicente

blau

He estado dándole vueltas a eso... y es en lo que estoy ... ;)

aunque si se pudiera hacer lo otro creo que se quedaría más transparente... pero en fin...

Vicente

Seguramente se pueda usar DynamicObject para esto tambien, pero no acabo de ver el como usarlo, me puedes poner un ejemplillo un poco mas concreto? (yo tambien ando un poco espeso :p).

blau

#4
Ya está hecho usando tipos genéricos...

Este es el código que lee el emsamblado buscando clases de TreeSharp, de momento, para las pruebas solo he definido las acciones...
Lo que hace es crear un tipo genérico que hereda de un tipo de Brainiac, que hace de wrapper y cuyo argumento es de un tipo proveniente de TreeSharp.
Código (csharp) [Seleccionar]

    Assembly a = Assembly.Load( "DarkTriadBehaviourTrees" );
    foreach ( Type t in a.GetTypes( ) )
    {
        if ( t.IsSubclassOf( typeof( TreeSharp.Action ) ) )
       {
            Type generic = typeof( Action<> );
            Type newType = generic.MakeGenericType( t );
             actions.Items.Add( newType );
       }
   }


Esta es la declaración del tipo genérico... donde se añade una propiedad del tipo proveniente de TreeSharp para poder acceder a sus propiedades desde el diseñador.
Código (csharp) [Seleccionar]

   public interface ITreeSharpNode<T>
   {
       T TreeSharpNode { get; set; }
   }

   public class Action<T>: Brainiac.Design.Nodes.Action, ITreeSharpNode<T> where T: TreeSharp.Action, new( )
   {
       public T TreeSharpNode { get; set; }
       public Action( ) : base( "Label", "Description" )
       {
           TreeSharpNode = new T( );
       }
   }



He modificado en el diseñador la función que obtiene las propiedades del objeto seleccionado, comprobando si es de tipo generico, y añadiendo tambien las del argumento genérico.

Código (csharp) [Seleccionar]

    List<DesignerPropertyInfo> list= new List<DesignerPropertyInfo>();

    PropertyInfo[] properties= type.GetProperties(BindingFlags.Instance|BindingFlags.Public);

           if ( type.IsGenericType )
           {
               List<PropertyInfo> pi = new List<PropertyInfo>( properties );
               Type[] genericArguments = type.GetGenericArguments( );
               foreach ( Type argument in genericArguments )
               {
                   pi.AddRange( argument.GetProperties( BindingFlags.Instance|BindingFlags.Public ) );
               }

               properties = pi.ToArray( );
           }


Y aquí están las funciones que substituyen a GetValue y SetValue en el diseñador para acceder correctamente al objeto que las posee
Código (csharp) [Seleccionar]

   public static class WrapperHelper
   {

       public static object GetWrappedValue( PropertyInfo pi, object defaultOwner )
       {
           try
           {
               return pi.GetValue( defaultOwner, null );
           }
           catch
           {
               var TreeSharpNodeProperty =  defaultOwner.GetType( ).GetProperties( ).FirstOrDefault( a => a.Name == "TreeSharpNode" );
               var Node = TreeSharpNodeProperty.GetValue( defaultOwner, null );

              return pi.GetValue( Node, null );
           }
       }

       public static void SetWrappedValue<T>( PropertyInfo pi, object owner, T value )
       {
           try
           {
               pi.SetValue( owner, ( T ) value, null );
           }
           catch
           {
               var TreeSharpNodeProperty =  owner.GetType( ).GetProperties( ).FirstOrDefault( a => a.Name == "TreeSharpNode" );
               var Node = TreeSharpNodeProperty.GetValue( owner, null );

               pi.SetValue( Node, ( T ) value, null );
           }
       }
   }


También he descubierto como se podría hacer de forma dinámica, aunque ya demasiado tarde,... http://mironabramson.com/blog/post/2008/06/Create-you-own-new-Type-and-use-it-on-run-time-(C).aspx

Mediante ModuleBuilder puedes definir un nuevo tipo que herede de una clase y añadirle las propiedades que quieras... que era justo lo que me hacía falta...

Vicente

Ouch, para usar el ModuleBuilder yo usaria dynamic la verdad, es mucho mas sencillo sobre todo si quieres anadir metodos y tal.

blau

Como se haría para que herede de una clase base con dynamic?

Vicente

Necesitas heredar? Normalmente tu clase hereda de DynamicObject o ExpandoObject, asi que no puede heredar de otra cosa. Si te hace falta heredar puedes utilizar IDynamicMetaProvider o algo asi, pero hace falta ser ingeniero de la NASA para implementar esa interfaz :p

blau

xD

pues por ingeniero de la nasa no me sale nada en mi agenda oiga... :P

de momento me voy apañando con la solución de usar genéricos derivados de las clases de brainiac y pasar como argumento del genérico el tipo derivado de treesharp.... ;) 

da gusto ir programando acciones  y que te vayan apareciendo los nodos correspondientes en el editor de forma automática...





Vicente

Espero que cuelgues uno de tus famosos videos de editores :D

blau

pues de este tendría que ser con permiso...  :..

ahora que por fin tengo tiempo me he embarcado en el desarrollo de un rpg por cuenta ajena... y otra cosa no... pero un buen editor de niveles van a tener... xD

Vicente

Pues nada, con capturas del RPG tambien nos conformamos :D

blau

  Bueno,

al final me han pedido que vaya actualizando un blog con las penurias y los avances que voy haciendo... hay más de las primeras...pero me quedo con los avances... :)

Este es el vídeo donde para no defraudar a @Vicente muestro un editor muy chulo aunque basado en Brainiac :

        http://www.youtube.com/watch?v=6uGg6bUYyUU&list=UUv2pMGQPRzuZAE0PrwZuzbg&index=0&feature=plcp

Y este el enlace al blog: http://autoloot-games.com/?p=110

Conforme vaya haciendo cosillas iré actualizándolo... aunque este mes que entra toca estudiar... y hasta Septiembre no retomaré el tema...  ;)

Un saludo...

XÑA


Vicente

Espectacular, vaya pedazo currada te has dado :O Enhorabuena!!!






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.