How do I set a class member value by its name in a string?

Biotronic simen.kjaras at gmail.com
Wed Dec 27 23:47:14 UTC 2017


On Wednesday, 27 December 2017 at 21:42:53 UTC, Mengu wrote:
> On Wednesday, 27 December 2017 at 21:39:49 UTC, Mengu wrote:
>> On Wednesday, 27 December 2017 at 20:54:17 UTC, bitwise wrote:
>>> [...]
>>
>> there's also a simple workaround for fields with the same 
>> type: https://run.dlang.io/is/dsFajq
>>
>> import std.stdio;
>>
>> struct S {
>>   int x;
>>   int y;
>> }
>>
>> auto setValue(ref S s, string field, int value) {
>>   foreach (fieldName; __traits(allMembers, S)) {
>>     if (fieldName == field) {
>>       __traits(getMember, s, fieldName) = value;
>>       break;
>>     }
>>   }
>> }
>>
>> void main() {
>>   S s;
>>   s.setValue("x", 5);
>>   s.setValue("y", 25);
>>   writeln(s);
>> }
>>
>>
>> you can play with it to make it more generic. you can also 
>> create a mixin template that would generate setters for each 
>> field you would need a setter for and then in the run time 
>> you'd just be able to call them.
>
> return type should just be void. that's just my muscle memory. 
> :-D

More generic, for more better:

void setValue(T, V)(auto ref T aggregate, string field, V value)
{
     import std.traits : FieldNameTuple;
     import std.meta : Alias;
     switch (field)
     {
         foreach (fieldName; FieldNameTuple!T)
         {
             case fieldName:
                 static if (is(typeof(__traits(getMember, 
aggregate, fieldName) = value)))
                 {
                     __traits(getMember, aggregate, fieldName) = 
value;
                     return;
                 }
                 else assert(false, T.stringof ~ "."~field~" 
cannot be assigned from a "~V.stringof~".");
         }
         default:
             assert(false, T.stringof ~ " has no field named 
"~field~".");
     }
}

unittest {
     import std.exception : assertThrown;
     import core.exception : AssertError;

     static struct S {
         int x;
         string s;
     }

     S s;
     s.setValue("x", 14);
     assert(s.x == 14);
     assertThrown!AssertError(s.setValue("q", 14));
     assertThrown!AssertError(s.setValue("s", 14));
     s.setValue("s", "abc123");
     assert(s.s == "abc123");
}

unittest {
     import std.exception : assertThrown;
     import core.exception : AssertError;

     static class C {
         int x;
         string s;
     }

     C c = new C;
     c.setValue("x", 14);
     assert(c.x == 14);
     assertThrown!AssertError(c.setValue("q", 14));
     assertThrown!AssertError(c.setValue("s", 14));
     c.setValue("s", "abc123");
     assert(c.s == "abc123");

     (new C).setValue("x", 143);
}

--
   Biotronic


More information about the Digitalmars-d-learn mailing list