jeudi 10 mai 2018

Why setting member through reflection fails to use custom conversion operator

I've got implicit conversion operator defined in my class to produce instance from string. I can set the variable using string literal but it fail if I try to do the same thing using reflection:

public class StringConvertable {

    public StringConvertable member;

    public StringConvertable(bool test = false) { if (!test) return;
        member = "this is ok :)";
        this.GetType().GetField(nameof(member))
            .SetValue(this, "this is not ok :(");
    }

    public static implicit operator
        StringConvertable(string s) => new StringConvertable();
}

this give me an error:

Obiektu typu 'System.String' nie można przekonwertować na typ 'Various.StringConvertable'.

Why I can't do this? What's the least invasive way to set members using reflection when I have only strings as an input?

Maybe there's a better way. Currently I solved this like that:

public class StringConvertable {

    public StringConvertable member;
    public int integer = int.MaxValue;
    public string stringg;

    public StringConvertable(bool test = false) { if (!test) return;
        member = "this is ok :)";
        setMember(nameof(member), "this is not ok :("); //now actually is :)
        setMember(nameof(integer), "123"); 
        setMember(nameof(integer), "abc");
        setMember(nameof(stringg), "Lorem ipsum dolor sit amet"); 
    }

    private void setMember(string name, string value) {
        var f = this.GetType().GetField(name);
        var c = tryConvert(value, f.FieldType);
        if (c.ok) f.SetValue(this, c.value);
        else if(!c.found) f.SetValue(this, name);
    }

    public static implicit operator
        StringConvertable(string s) => new StringConvertable();

    private (bool found, bool ok, object value) tryConvert(string s, Type t) {
        foreach (var c in converts) {
            if (c.type != t) continue;
            var r = c.convert(s, t);
            return (true, r.ok, r.value);
        }return (false, false, null);
    }

    private List<StringConverter> converts = new List<StringConverter>() {
        new StringConverter(typeof(StringConvertable),
            (s,t) => (true, (StringConvertable)s)),
        new StringConverter(typeof(int),
            (s,t) => (int.TryParse(s, out int v), v))
    };
}

public class StringConverter {
    public Type type { get; private set; }
    public Converter convert { get; private set; }
    public StringConverter(Type t, Converter c) {
        type = t;
        convert = c;
    }

    public delegate (bool ok, object value) Converter(string s, Type t); 
}





Aucun commentaire:

Enregistrer un commentaire