Call method if declared only
    Simen Kjærås 
    simen.kjaras at gmail.com
       
    Fri Feb 28 09:12:38 UTC 2020
    
    
  
On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote:
> Searching solution for idea !
For whatever reason, it seems my attempts at answering this 
earlier has disappeared into the void. Here:
import core.sys.windows.windows;
import std.stdio;
class Base {
     LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
         switch (message) {
             case WM_KEYDOWN:
                 return tryCall!"OnWM_KEYDOWN"(wParam, lParam);
             default:
         }
         return 0;
     }
     auto tryCall(string name, Args...)(Args args) {
         import std.meta;
         alias This = typeof(this);
         alias module_ = __traits(parent, This);
         enum isSubclass(T...) = is(T[0] : This);
         alias getModuleMember(string name) = __traits(getMember, 
module_, name);
         enum hasMethod(T) = __traits(hasMember, T, name);
         // Get every member in this module
         enum memberNames = __traits(allMembers, module_);
         alias members = staticMap!(getModuleMember, memberNames);
         // Filter away anything that isn't derived from Base
         alias subclasses = Filter!(isSubclass, members);
         // Get rid of anything that doesn't have a method with 
the correct name
         alias subclassesWithMethod = Filter!(hasMethod, 
subclasses);
         // Sort them so you get the most derived types first
         alias Types = DerivedToFront!subclassesWithMethod;
         // Check for each type if the `this` is an instance of 
that specific one
         static foreach (T; Types) {
             if (cast(T)this !is null) {
                 // And look up that method and call it.
                 return __traits(getMember, cast(T)this, 
name)(args);
             }
         }
         // If `this` is not one of the types with that method, 
return some default value
         return 0;
     }
}
class Button : Base {
     LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
         writeln("WM_KEYDOWN");
         return 0;
     }
}
unittest {
     Base b1 = new Base();
     Base b2 = new Button();
     writeln("Base:");
     b1.On(WM_KEYDOWN, 0, 0);
     writeln("Button:");
     b2.On(WM_KEYDOWN, 0, 0);
}
Now, this only works for subclasses defined in the same module. A 
possibly better solution would be interfaces:
import core.sys.windows.windows;
import std.stdio;
class Base {
     LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
         switch (message) {
             case WM_KEYDOWN:
                 if (cast(IKeyDown)this) {
                     return 
(cast(IKeyDown)this).OnWM_KEYDOWN(wParam, lParam);
                 }
             default:
         }
         return 0;
     }
}
interface IKeyDown {
     LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam);
}
class Button : Base, IKeyDown {
     LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
         writeln("WM_KEYDOWN");
         return 0;
     }
}
unittest {
     Base b1 = new Base();
     Base b2 = new Button();
     writeln("Base:");
     b1.On(WM_KEYDOWN, 0, 0);
     writeln("Button:");
     b2.On(WM_KEYDOWN, 0, 0);
}
--
   Simen
    
    
More information about the Digitalmars-d-learn
mailing list