digitalmars.D.learn - Reflection in D
- medhi558 (7/7) Jan 27 2017 Hello, I would like to know if it is possible to recover all
- Adam D. Ruppe (4/6) Jan 27 2017 Yes, `foreach(mod; ModuleInfo) foreach(lc; mod.localClasses)`...
- medhi558 (53/53) Jan 27 2017 I develop a game server. Currently I use a switch :
- medhi558 (6/6) Jan 27 2017 I have a last question, currently i use :
- rumbu (5/11) Jan 27 2017 if (auto nm = cast(NetworkMessage)lc)
- medhi558 (2/17) Jan 28 2017 It doesn't work because lc is TypeInfo_Class
- Adam D. Ruppe (23/25) Jan 28 2017 If they're all in the same module, you can also use the compile
- medhi558 (33/33) Jan 28 2017 thank you, the second method works perfectly.
- rumbu (7/17) Jan 28 2017 As long as your class has a default constructor, you can use
- medhi558 (17/23) Jan 28 2017 It isn't possible. My function when I receive data :
Hello, I would like to know if it is possible to recover all classes in the project in D. Assembly asm = Assembly.GetAssembly(typeof(MyClass)); foreach (Type type in asm.GetTypes()) { }
Jan 27 2017
On Friday, 27 January 2017 at 21:02:13 UTC, medhi558 wrote:Hello, I would like to know if it is possible to recover all classes in the project in D.Yes, `foreach(mod; ModuleInfo) foreach(lc; mod.localClasses)`... but why do you want it? That facility is kinda limited in doing many things with.
Jan 27 2017
I develop a game server. Currently I use a switch : import protocol.messages.connection.Message1; import protocol.messages.connection.Message2; import protocol.messages.queues.Message3; import ...... import protocol.messages.NetworkMessage; class ProtocolMessageManager { public static NetworkMessage GetInstance(uint id) { switch(id) { case Message1.Id: return new Message1(); case Message2.Id: return new Message2(); ..... default: return null; } } } what I want to do : import protocol.messages.NetworkMessage; class ProtocolMessageManager { private static TypeInfo_Class[uint] m_types; public static void Init() { foreach(mod; ModuleInfo) { foreach(TypeInfo_Class lc; mod.localClasses) { if(lc.name.indexOf("protocol.messages") != -1) { NetworkMessage c = cast(NetworkMessage)lc.create(); ProtocolMessageManager.m_types[c.MessageId] = lc; } } } } public static NetworkMessage GetInstance(string id) { auto v = (id in ProtocolMessageManager.m_types); if (v !is null) return cast(NetworkMessage)ProtocolMessageManager.m_types[id].create(); else return null; } }
Jan 27 2017
I have a last question, currently i use : if(lc.name.indexOf("protocol.messages") != -1) To know if the class is a NetworkMessage, Would be possible to do this if(lc is NetworkMessage) Sorry for my English, i speak french.
Jan 27 2017
On Saturday, 28 January 2017 at 07:10:27 UTC, medhi558 wrote:I have a last question, currently i use : if(lc.name.indexOf("protocol.messages") != -1) To know if the class is a NetworkMessage, Would be possible to do this if(lc is NetworkMessage) Sorry for my English, i speak french.if (auto nm = cast(NetworkMessage)lc) { //do something with nm }
Jan 27 2017
On Saturday, 28 January 2017 at 07:39:51 UTC, rumbu wrote:On Saturday, 28 January 2017 at 07:10:27 UTC, medhi558 wrote:It doesn't work because lc is TypeInfo_ClassI have a last question, currently i use : if(lc.name.indexOf("protocol.messages") != -1) To know if the class is a NetworkMessage, Would be possible to do this if(lc is NetworkMessage) Sorry for my English, i speak french.if (auto nm = cast(NetworkMessage)lc) { //do something with nm }
Jan 28 2017
On Saturday, 28 January 2017 at 08:18:15 UTC, medhi558 wrote:On Saturday, 28 January 2017 at 07:39:51 UTC, rumbu wrote:In this case: if (lc == typeid(NetworkMessage))On Saturday, 28 January 2017 at 07:10:27 UTC, medhi558 wrote:It doesn't work because lc is TypeInfo_ClassI have a last question, currently i use : if(lc.name.indexOf("protocol.messages") != -1) To know if the class is a NetworkMessage, Would be possible to do this if(lc is NetworkMessage) Sorry for my English, i speak french.if (auto nm = cast(NetworkMessage)lc) { //do something with nm }
Jan 28 2017
abstract class NetworkMessage { uint MessageId; //.... } override class QueueStatusUpdateMessage : NetworkMessage { uint MessageId = 1; //.... } override class Message2 : NetworkMessage { uint MessageId = 2; //.... } override class Message3 : NetworkMessage { uint MessageId = 3; //.... } And I would like to retrieve all the classes that are based on NetworkMessage. class ProtocolMessageManager { private static TypeInfo_Class[uint] m_types; public static void Init() { foreach(mod; ModuleInfo) { foreach(TypeInfo_Class lc; mod.localClasses) { if(....) //lc is NetworkMessage so { NetworkMessage c = cast(NetworkMessage)lc.create(); ProtocolMessageManager.m_types[c.MessageId] = lc; } } } } public static NetworkMessage GetInstance(string id) { auto v = (id in ProtocolMessageManager.m_types); if (v !is null) return cast(NetworkMessage)ProtocolMessageManager.m_types[id].create(); else return null; } }
Jan 28 2017
On Saturday, 28 January 2017 at 07:10:27 UTC, medhi558 wrote:I have a last question, currently i use : if(lc.name.indexOf("protocol.messages") != -1)If they're all in the same module, you can also use the compile time reflection to scan the module for classes. That's foreach(memberName; __traits(allMembers, mixin(__MODULE__))) static if(is(__traits(getMember, mixin(__MODULE__), memberName) : NetworkMessage) { if(memberName == runtime_string_of_class_name) { auto msg = new __traits(getMember, mixin(__MODULE__), memberName); // populate msg } } Or something like that. The compile time stuff works well when everything is in a shared module. If not, the runtime stuff has methods `base` and `interfaces` you can scan for your class. So like foreach(c; mod.localClasses if(c.base is typeid(NetworkMessage) { // work with it } Notice it is typeid for runtime, typeof at compile time, and this only gets direct children of NetworkMessage (though you could walk up the parent list to check more).
Jan 28 2017
thank you, the second method works perfectly. I have one last problem, I start thread and in thread Protocol.GetInstance(id) return null while in main thread it works. My class : class ProtocolMessageManager { private static TypeInfo_Class[uint] m_types; shared static this() { foreach(mod; ModuleInfo) { foreach(TypeInfo_Class lc; mod.localClasses) { if(lc.base is typeid(NetworkMessage)) { NetworkMessage c = cast(NetworkMessage)lc.create(); ProtocolMessageManager.m_types[c.MessageId] = lc; } } } } public static NetworkMessage GetInstance(uint id) { auto v = (id in ProtocolMessageManager.m_types); if (v !is null) return cast(NetworkMessage)ProtocolMessageManager.m_types[id].create(); else return null; } }
Jan 28 2017
On Saturday, 28 January 2017 at 07:03:51 UTC, medhi558 wrote:public static NetworkMessage GetInstance(string id) { auto v = (id in ProtocolMessageManager.m_types); if (v !is null) return cast(NetworkMessage)ProtocolMessageManager.m_types[id].create(); else return null; } }As long as your class has a default constructor, you can use directly Object.factory(id): public static NetworkMessage GetInstance(string id) { return cast(NetworkMessage)(Object.factory(id)); }
Jan 28 2017
On Saturday, 28 January 2017 at 09:05:13 UTC, rumbu wrote:As long as your class has a default constructor, you can use directly Object.factory(id): public static NetworkMessage GetInstance(string id) { return cast(NetworkMessage)(Object.factory(id)); }It isn't possible. My function when I receive data : private void ReceivedData(char[] buffer) { BinaryReader reader = new BinaryReader(); uint id = reader.ReadUInt(); uint length = reader.ReadInt(); if(length > reader.Available.length) { //waiting for the rest return; } NetworkMessage message = ProtocolMessageManager.GetInstance(id); message.Deserialize(); //..... }
Jan 28 2017