如果需要,在转换类型时通过 Ref 设置属性



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

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

您看到的接口在与 all 相同的命名空间中实现如下:

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"的属性值排序,这意味着,通过实际从字符串调用属性的名称。 我正在尝试,但无法解决两个问题。我无法设置"链接"属性值,或者由于我在界面中的错误而导致实现中的某些内容无法正常工作。 其次,同样重要的是,我无法读取和转换属性,即我只有字符串作为值,有时属性是布尔值、整数、双精度、日期时间等。 现在,我知道转换是一个很大的主题,所以我想尝试阅读属性类型并通过 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 字符串中找到它们(。欢迎任何帮助..

也许使用反射?

要设置:

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。也许你应该研究一下。

如果该属性不是顶级属性,那么我们需要指向目标属性的路径,在本例中,路径是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# <8.0

根据你的注释,你使用的是 C# 版本 <8.0,其中原始响应中使用的某些功能不可用(如范围运算符^(。我在.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));
}

最新更新