【问题标题】:Setting property by Ref while converting Type if needed如果需要,在转换 Type 时通过 Ref 设置属性
【发布时间】:2020-05-14 12:09:29
【问题描述】:

我有一系列复杂的类,我在这里放了一个可以编译和工作的最小示例:

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);
    }
}

我正在尝试通过实际调用字符串中的属性名称来实现设置属性值排序为“by ref”。 我正在尝试但无法解决两个问题。我无法设置“链接”属性值,或者由于我在接口中的错误,实现中的某些内容无法正常工作。 其次,同样重要的是,我无法读取和转换属性,即我只有字符串作为值,有时属性是 bool、int、double、DateTime 等。 现在,我知道转换是一个大课题,所以我想尝试读取属性类型并通过 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 字符串中找到了它们)。欢迎任何帮助..

【问题讨论】:

  • 那个界面是空的,这是你首先应该避免的。我没有得到的另一件事是你到底想要达到什么目标,或者你试图这样做的原因是什么。你能解释一下你想要达到的目标吗?也许会有更简单的方法让它工作。
  • @John 感谢您的意见。我正在尝试实现 myClass.SetPropertyAsString("include", "true"); 所以,我确实有一个我必须阅读的 json 字符串,它与您在上面看到的类的结构完全匹配。所以我试图读取 json "side": "true",然后在类中找到这个属性并将其设置为 true,依此类推。问题是,我首先必须查看该属性在哪里(可能不是直接在第一个类中,而是在示例中的“链接”类中),然后尝试使用 SetValue 分配值。

标签: c# properties typeof


【解决方案1】:

也许使用反射?

设置:

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)来解决。也许你应该调查一下。

【讨论】:

    【解决方案2】:

    如果属性不是顶级属性,那么我们需要指向目标属性的路径,在我们的例子中路径是member:side:include。我在这里使用: 作为分隔符。

    //top-level property
    myClass.SetPropertyAsString("num", "88");
    
    //nested properties
    myClass.SetPropertyAsString("member:side:include", "true");
    myClass.SetPropertyAsString("part:seriesNum", "15");
    

    然后修改反射代码,使其可以沿着给定的路径前进:

    //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#

    根据您的 cmets,您使用的 C# 版本 ^)。我在.NET 4.7.2C# 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));
    }
    

    【讨论】:

    • 非常感谢,我已经尝试过,但似乎做不到 - 在var keys = propertyName.Split(":"); throws 中无法从字符串转换为字符(var property = current.GetType().GetProperty(key);key 相同。) .我试图提供额外的参数StringSplitOptions.None,但仍然抛出相同的错误。而且,在 foreach 中,keys[0..^ 1]) 无法识别 .^(“预期标识符”)。
    • 你能帮上忙吗?看来您的解决方案可以工作..谢谢!
    • @Nick 不客气!我已使用不使用 C# 8.0 功能的版本更新了我的答案。
    • 非常感谢,请帮我做一件小事,它返回未设置对象实例的对象引用,错误引用到current = property.GetValue(current) as IMPropertyAsStringSettable;行和关于@ 987654338@我不太明白...你能帮帮我吗?
    • 这是工作代码的fiddle。如果没有完整的异常消息和可能的调试器,很难说,但我认为错误是由输入引起的(你如何调用函数并形成路径,即路径与属性名称不匹配),或者可能会创建一个包含更多详细信息的新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    • 1970-01-01
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多