How to set a property of a class by string name?

This is a working in progress, I need to create an object with info got from a xml file - a metadata.

Here is the metadata, the text to construct the object:

Creator:Gustavo Jesien Pinent
Subject:How to play Rescue Space Miners
Description:Multilanguage text structured into fields
Publisher:Virtualis
Date:2020-05-06
Type:MultiLanguageSimpleText
Format:UTF-8,URI
Identifier:Instructions1
Language:pt=Português,en=English,es=Español
Rights:GPL3.0```

This is the code:

```csharp
public class DCPMetadata
{
    private Dictionary<string, string> FieldTypes = new Dictionary<string, string>()
    {
        { "Title", "string" },
        { "Creator", "string" },
        { "Subject", "string" },
        { "Description", "object" },
        { "Publisher", "string" },
        { "Contributer", "string" },
        { "Date", "DateTime" },
        { "Type", "string" },
        { "Format", "string" },
        { "Identifyer", "string" },
        { "Source", "string" },
        { "Language", "Dictionary" },
        { "Relation", "string" },
        { "Coverage", "string" },
        { "Rights", "string" }
    };

    public string Title;
    public string Creator;
    public string Subject;
    public object Description;
    public string Publisher;
    public string Contributer;
    public DateTime Date;
    public string Type;
    public string Format;
    public string Identifyer;
    public string Source;
    public Dictionary<string, string> Language;
    public string Relation;
    public string Coverage;
    public string Rights;

    public List<string> Errors { get; private set; }

    public DCPMetadata(string text)
    {
        this.Errors = new List<string>();
        string[] Lines = text.Split('\n');
        foreach (string line in Lines)
        {
            string l = line.Trim();
            string[] E = l.Split(':');
            if (this.FieldTypes.ContainsKey(E[0]))
            {
                string type = this.FieldTypes[E[0]];
                switch (type)
                {
                    case "object":
                        // not implemented yet...
                        break;
                    case "Date":
                        this[E[0]] = System.DateTime.Parse(E[1]);
                        break;
                    case "Dictionary":
                        string[] pairs = E[1].Split(',');
                        Dictionary<string, string> D = new Dictionary<string, string>();
                        foreach (string pair in pairs)
                        {
                            string[] T = pair.Split('=');
                            D.Add(T[0], T[1]);
                        }
                        this[E[0]] = D;
                        break;
                    case "string":
                        this[E[0]] = E[1];
                        break;
                }
            }
            else
            {
                this.Errors.Add("DCPMetadata construction ERROR: field '" + E[0] + "' non standard.");
            }
        }
    }

    public object this[string propertyName] // need System.Reflection
    {
        get
        {
            // probably faster without reflection:
            // like:  return Properties.Settings.Default.PropertyValues[propertyName]
            // instead of the following
            Type myType = GetType();
            PropertyInfo myPropInfo = myType.GetProperty(propertyName);
            if (myPropInfo != null) return myPropInfo.GetValue(this, null);
            else return null;
        }
        set
        {
            Type myType = GetType();
            PropertyInfo myPropInfo = myType.GetProperty(propertyName);
            if(myPropInfo != null) myPropInfo.SetValue(this, value, null);
        }
    }

}

I’d pick the code that set the property by string around the web but can’t make it work. myPropInfo is always null, if I remove the ‘if’, I got a Null Reference Error. Why?

There are lots of off-the-shelf libraries you could use for serializing/deserializing objects to/from XML or JSON. Unless you have a rather good reason to write your own, your life will probably be easier if you pick one of the existing ones to use instead.

1 Like

I am not trying to deserialize a XML, I just store the texts inside tags to be easy to pick up. The problem is at the bottom of the code when I try to set a value of a property witch name is a string.

Use this version of GetProperty Type.GetProperty Method (System) | Microsoft Learn and make sure you provide the appropriate BindingFlags.

It does not work! I also created a “test” property to return a string by name just to check if it was some null error prior than DCPMetadata.

public object this[string propertyName] // need System.Reflection
    {
        get
        {
            // probably faster without reflection:
            // like:  return Properties.Settings.Default.PropertyValues[propertyName]
            // instead of the following
            Type myType = GetType(); //typeof(DCPMetadata);//
            Console.WriteLine("myType: " + myType);
            PropertyInfo myPropInfo = myType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
            Console.WriteLine("myPropInfo: " + myPropInfo);
            if (myPropInfo != null) return myPropInfo.GetValue(this, null);
            else return null;
        }
        set
        {
            Type myType = GetType(); //typeof(DCPMetadata);//
            Console.WriteLine("myType: " + myType);
            PropertyInfo myPropInfo = myType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
            Console.WriteLine("myPropInfo: " + myPropInfo);
            if (myPropInfo != null) myPropInfo.SetValue(this, value, null);
        }
    }

Also the Console.WriteLine does not write anything in my console.

I am not sure about how this BindingFlags do operate, but I am considering some error of C# interpretation by Unity…

I think the variable you are trying to access is a Field, not a Property. Therefore you have to use Type.GetField()

1 Like

Indeed! I did a research and some tests, it was not being listed in properties, but in fields list. Therefore it might be easier just to change property to field, I decided to change those fields to properties like this…

    public string Title { get; set; }
    public string Creator { get; set; }
    public string Subject { get; set; }
    public object Description { get; set; }
    public string Publisher { get; set; }
    public string Contributer { get; set; }
    public DateTime Date { get; set; }
    public string Type { get; set; }
    public string Format { get; set; }
    public string Identifyer { get; set; }
    public string Source { get; set; }
    public Dictionary<string, string> Language { get; set; }
    public string Relation { get; set; }
    public string Coverage { get; set; }
    public string Rights { get; set; }

As I did read, a field should be private, so a method is specified to access it from outside (just starting to understand this all stuff). I came from JavaScript and PHP and many concepts of C# are still new to me…

1 Like