Установка свойства по Ref при преобразовании Type, если это необходимо - PullRequest
0 голосов
/ 29 января 2020

У меня сложная серия классов, я поместил здесь минимальный пример, который компилируется и работает:

public class DataClass : IMPropertyAsStringSettable
{
    public int num { get; set; }
    public string code { get; set; }
    public PartClass part { get; set; }
    public MemberClass member { get; set; }
    public DataClass()
    {
        part = new PartClass();
        member = new MemberClass();
    }
}
public class PartClass : IMPropertyAsStringSettable
{
    public int seriesNum { get; set; }
    public string seriesCode { get; set; }
}
public class MemberClass : IMPropertyAsStringSettable
{
    public int versionNum { get; set; }
    public SideClass side { get; set; }
    public MemberClass()
    { 
        side = new SideClass();
    }
}
public class SideClass : IMPropertyAsStringSettable
{
    public string firstDetail { get; set; }
    public string secondDetail { get; set; }
    public bool include { get; set; }
}

Интерфейс, который вы видите, реализован следующим образом в том же пространстве имен, что и все:

public interface IMPropertyAsStringSettable { }

public static class PropertyAsStringSettable
{
    public static void SetPropertyAsString(this IMPropertyAsStringSettable self, string propertyName, string value)
    {
        var property = TypeDescriptor.GetProperties(self)[propertyName];
        var convertedValue = property.Converter.ConvertFrom(value);
        property.SetValue(self, convertedValue);
    }
}

Я пытаюсь добиться установки значения свойства, вроде 'по ref', то есть путем фактического вызова имени свойства из строки. Я пытаюсь, но не могу решить две проблемы. Я не могу установить значения свойств «связанных», или что-то в реализации не работает должным образом из-за моей ошибки в интерфейсе. И, во-вторых, что не менее важно, я не могу прочитать и преобразовать свойство, т. Е. У меня есть только строки в качестве значений, а иногда это свойства bool, int, double, DateTime et c. Теперь я знаю, что конверсия - большая тема, поэтому я решил попробовать прочитать тип свойства и выполнить конвертацию через try / catch, но не смог.

Это то, чего я пытаюсь достичь ( основываясь на приведенном выше фрагменте кода):

        static int Main(string[] args)
    {
        //just initializing the whole thing without
        //setting values to properties
        DataClass myClass = new DataClass()
        {
            part = new PartClass(),
            member = new MemberClass()
            {
                side = new SideClass()
            }
        };

        // here I read from a source names and values.....

        //and I am trying to populate like this:

        myClass.SetPropertyAsString("include", "true"); //this property is in SideClass, and also a bool
        myClass.SetPropertyAsString("seriesNum", "88"); //this property is in PartClass and an int..

Для непосредственного использования в качестве:

        //This should print "True"
        Console.WriteLine("myClass member side include = " + myClass.member.side.include.ToString());

        Console.ReadKey();
        return 0;
    }

Я действительно надеюсь, что кто-то может помочь, я не эксперт в этом; Если бы вы могли предоставить рабочий фрагмент кода, основанный на вышеизложенном, я был бы очень признателен. Спасибо всем

Примечание: использование отражения может работать лучше (попытка присвоить значения всем свойствам, которые я нашел в строке JSON). Любая помощь приветствуется ..

Ответы [ 2 ]

0 голосов
/ 29 января 2020

Если свойство не относится к верхнему уровню, нам нужен путь, ведущий к целевому свойству, в нашем случае это member:side:include. Я использую здесь : в качестве разделителя.

//top-level property
myClass.SetPropertyAsString("num", "88");

//nested properties
myClass.SetPropertyAsString("member:side:include", "true");
myClass.SetPropertyAsString("part:seriesNum", "15");

Затем измените код отражения, чтобы он мог go по заданному пути:

//will handle both nested and top-level properties
public static void SetPropertyAsString(this IMPropertyAsStringSettable self, string propertyName, string value) {
    //current, is in a way, the property iterator
    var current = self;

    var keys = propertyName.Split(":");

    //iterate over keys till the key before last -since the last key is the target property-
    foreach (var key in keys[0..^1]) {
        var property = current.GetType().GetProperty(key);
        current = property.GetValue(current) as IMPropertyAsStringSettable;
    }

    var targetProperty = current.GetType().GetProperty(keys.Last());

    //convert the input value to the data type of the target property, and set it to the target property
    targetProperty.SetValue(current, Convert.ChangeType(value, targetProperty.PropertyType));
}

РЕДАКТИРОВАТЬ: для C# <8.0 </strong>

На основании ваших комментариев вы используете C# версию <8.0, где некоторые функции, использованные в исходном ответе, недоступны (например, оператор дальности <code>^). Я скомпилировал следующее на .NET 4.7.2, C# 7.3 и выдал тот же результат.

public static void SetPropertyAsString(this IMPropertyAsStringSettable self, string propertyName, string value) {
    var current = self;
    var keys = propertyName.Split(':');
    for (var i = 0; i < keys.Length - 1; i++) {
        var property = current.GetType().GetProperty(keys[i]);
        current = property.GetValue(current) as IMPropertyAsStringSettable;
    }
    var targetProperty = current.GetType().GetProperty(keys[keys.Length - 1]);
    targetProperty.SetValue(current, Convert.ChangeType(value, targetProperty.PropertyType));
}
0 голосов
/ 29 января 2020

Может быть, использовать отражение?

Чтобы установить:

var type = self.GetType();
var property = type.GetProperty(propertyName);
var convertedValue = Convert.ChangeType(value, property.PropertyType);
property.SetValue(self, convertedValue);

Чтобы получить:

public T GetPropertyValue<T>(this IYourInterface self, string name) 
{
   var type = self.GetType();
   var property = type.GetProperty(propertyName);
   return (T) property.GetValue(self);
}

Я не очень хорошо понимаю, почему вы действительно хотите это сделать Кажется действительно странным, проблема может быть решена с помощью сериализации в стандартный формат, например JSON. Может быть, вы должны посмотреть на это.

...