jeudi 9 juillet 2020

How can I iterate a complex type 's members for user-supplied values?

For POD type classes, I have code like this which allows a user to specify values without needing external scripts, through simple reflection:

class Message
{
 public int Id{get;set;}
 public string name{get;set}
 public int FaultCode{get;set;}
}

    public void Configure(Message msg)
    {
        var type = msg.GetType();
        var properties = type.GetProperties().Where(p => p.CanWrite).ToArray();
        
        for (var i = 0; i < properties.Length; ++i)
        {
            var prop = properties[i];
            var str = PromptForInput("Enter {0} value for {1}.{2} or ENTER to leave", prop.PropertyType.Name, msg.GetType().Name, prop.Name);
            if (str.Length == 0)
                continue;
            try
            {
                var val = Convert.ChangeType(str, prop.PropertyType);
                prop.SetValue(msg, val);
            }
            catch (Exception e)
            {
                ... //stuff
            }
        }
    }

But inevitably I end up with a message protocol that isn't simple POD:

class Fault
{
 public int FaultCode{get;set;}
 public int Severity{get;set;}
} 
class Message2
{
 public int Id{get;set;}
 public string name{get;set}
 public Fault[] Faults{get;set;}
}

For one or two such types custom logic in code would be quicker but if there are many, it would be nice to extend my reflection-based approach.

I'm wondering how best to do this issues such as:

  • how to tell which properties should be read as simple types, which should be nested
  • how to tell which properties are collections (so we ask the user to specify the number of elements)
  • how to set min/maximum size for collections

I was wondering if applying some simple attributes to my class members would be a good approach, to highlight which fields should be prompted/ignored (instead of all public writable properties), etc. But I've never used them before to know if that ends up being a lot of extra work defining custom attributes. Or if I can use attributes as simple metadata that can be read using reflection?

My Message2 is about as complex as it gets - I can limit collections to Array rather than List or whatever. Any suggestion how to neatly do this is welcome. It's for use in test-harness code not production so it can be a bit rough.





Aucun commentaire:

Enregistrer un commentaire