-2

In C# I have a struct with many fields, e.g. one called "key". I'm reading an .ini settings file, which has values for all the struct fields. Is there a way to use the field names as strings (like the myField string array below) to address the struct fields during the reading process (see below)? This would allow me to iterate the reading of many fields in a loop based on a string array.

private struct Foo {
  public string key;
  ...
}

private Foo FooInstance;
string inStr;
string[] myFields[] = new string[10]{ ("key", "nextKey", ... );

for (int i=0;i<myFields.Length;i++) {
  GetPrivateProfileString(section,myFields[i],"",inStr,255,file);
  [convert myField[i] to the relevant Foo.key field] = inStr;
}
T.S.
  • 18,195
  • 11
  • 58
  • 78
MrSparkly
  • 627
  • 1
  • 7
  • 17
  • 2
    *"I have a struct with many fields"* - actually it is not recommended to make struct more than 16 bytes – T.S. Mar 31 '20 at 00:53
  • **[Choosing Between Class and Struct](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct)** – Ňɏssa Pøngjǣrdenlarp Mar 31 '20 at 00:54
  • 1
    Are you reinventing `config` files? Why not JSON and newtonsoft, which will serialize/deserialize things for you? – T.S. Mar 31 '20 at 00:56
  • This is an abysmal coding practice. You really should at least store your data in a Dictionary in this case. The answer you marked as best is technically correct, but a very bad way of solving your issue. Reflection should be avoided when it is not necessary – Eugen1344 Mar 31 '20 at 02:11

1 Answers1

1

Combine reflection technique from this SO answer and keep in mind that struct is a value type so you need to correctly handle passing it back after you updated it.

A very quick solution might look like so:

struct Foo { 
    public string Key;
    public string NextKey;
}
static class FooExtensions
{
    public static void Set(this ref Foo obj, string key, string value) {
        object boxed = obj; // need to box the value type so we can use it after SetValue  
        var f = typeof(Foo).GetField(key, BindingFlags.Public|BindingFlags.Instance);
        f.SetValue(boxed, value);
        obj = (Foo) boxed;
    }

    public static string Get(this Foo obj, string key)
    {
        var f = typeof(Foo).GetField(key, BindingFlags.Public|BindingFlags.Instance);
        return (string)f.GetValue(obj);
    }
}
void Main()
{   
    var f = default(Foo);   
    f.Set("Key", "test");
    f.Set("NextKey", "test");   
    f.Get("Key").Dump();
}
timur
  • 14,239
  • 2
  • 11
  • 32
  • Thank you. In the answer you linked to, there's this line (I modified it for my naming). Wouldn't it do the same thing as your Extensions in a simpler in-line way?FooInstance.GetType().GetField("key").SetValueDirect(__makeref(FooInstance), inStr) – MrSparkly Mar 31 '20 at 01:45
  • 1
    potentially, it looks very similar, i haven't tested it. i personally find extension method easy to deal with. Just keep in mind you need correct BindingFlags to get fields and look out for that boxing gotcha – timur Mar 31 '20 at 01:58
  • the Set() extension works, but Get() gives me this exception: System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.String' at Example.FeedExtensions.Get(Foo obj, String key). Any idea what's wrong? Thanks. – MrSparkly Apr 04 '20 at 02:13
  • @MrSparkly your Foo probably has a an integer value, where Get assumes it's always a string. Try Convert.ToString() instead of direct cast in the method? – timur Apr 04 '20 at 02:43