Thread overview |
---|
December 27, 2017 How do I set a class member value by its name in a string? | ||||
---|---|---|---|---|
| ||||
I'd like to set the members of a class by its name at runtime, I would do something like this:
> __traits(getMember, myClass, name) = value;
but since name is only know at runtime, I can't use __traits(). What's a workaround for this?
|
December 27, 2017 Re: How do I set a class member value by its name in a string? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc | On Wednesday, 27 December 2017 at 20:04:29 UTC, Marc wrote:
> I'd like to set the members of a class by its name at runtime, I would do something like this:
>
>> __traits(getMember, myClass, name) = value;
>
> but since name is only know at runtime, I can't use __traits(). What's a workaround for this?
You will have to use a combination of compile time and runtime methologies.
Essentially what you want is this:
void setMemberValue(string name, int value)
{
switch(name)
{
case "member1":
member1 = value;
break;
case "member2":
member2 = value;
break:
...
}
}
As you don't want to write this for all members by hand you should write a function which generates the source code for this switch using static foreach and __traits(allMembers) and then mixin the generated string into the setMemberValue method. If your members can have different types you will also need runtime type that can hold multiple types. For simplicity I just used "int" in the above example. You could use "std.variant" for this.
|
December 27, 2017 Re: How do I set a class member value by its name in a string? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc | On Wednesday, 27 December 2017 at 20:04:29 UTC, Marc wrote: > I'd like to set the members of a class by its name at runtime, I would do something like this: > >> __traits(getMember, myClass, name) = value; > > but since name is only know at runtime, I can't use __traits(). What's a workaround for this? I think you could write something using a combination of these two things: https://dlang.org/phobos/std_traits.html#FieldNameTuple https://dlang.org/phobos/std_traits.html#Fields or maybe '.tupleof': https://dlang.org/spec/struct.html#struct_properties |
December 27, 2017 Re: How do I set a class member value by its name in a string? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | On Wednesday, 27 December 2017 at 20:54:17 UTC, bitwise wrote: > On Wednesday, 27 December 2017 at 20:04:29 UTC, Marc wrote: >> I'd like to set the members of a class by its name at runtime, I would do something like this: >> >>> __traits(getMember, myClass, name) = value; >> >> but since name is only know at runtime, I can't use __traits(). What's a workaround for this? > > I think you could write something using a combination of these two things: > > https://dlang.org/phobos/std_traits.html#FieldNameTuple > https://dlang.org/phobos/std_traits.html#Fields > > or maybe '.tupleof': > > https://dlang.org/spec/struct.html#struct_properties 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. |
December 27, 2017 Re: How do I set a class member value by its name in a string? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mengu | 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
|
December 27, 2017 Re: How do I set a class member value by its name in a string? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mengu | 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 |
December 28, 2017 Re: How do I set a class member value by its name in a string? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Biotronic | On Wednesday, 27 December 2017 at 23:47:14 UTC, Biotronic wrote:
> [...]
much, much better. thanks biotronic.
|
Copyright © 1999-2021 by the D Language Foundation