【问题标题】:Best way to assign property value dynamically based on the property name根据属性名称动态分配属性值的最佳方法
【发布时间】:2013-12-07 08:40:05
【问题描述】:

我有一个正在迭代的列表。

在 List 中是 Argument 类,其中包含两个属性“PropertyName”和“Value”

我需要做的是遍历参数集合并将该参数的值分配给不同类的属性(与当前参数同名)。

例子:

Argument:
     PropertyName: ClientID
            Value: 1234
Members Class:
     ClientID = {Argument Value here}

我希望这是有道理的。我有办法做到这一点,硬编码我的类的属性并将其与参数列表匹配。

类似:

foreach(var arg in List<Argument>)
{
    Members.ClientID = arg.Find(x => compareName(x, "ClientID")).Value;
    //where compareName just does a simple string.Compare
}

但是对于这样的事情,最好的方法是什么?

编辑:对这些家伙表示抱歉,并感谢到目前为止的回复。这是我没有提到的,可能会有所作为。

每个参数是同一类的不同属性。我正在遍历列表,其中的每一个都将用于我必须填充的相同成员类。

我想提到这一点,因为我在 foreach 中考虑我可能必须使用一个开关来确定我对该参数有什么“属性名称”。 ClientID 就是其中之一,但我相信 Members 类中总共有 14 个属性需要从 Collection 中填充。

这会改变事情吗?

再次感谢

【问题讨论】:

  • 能否请您发布Argument 类的定义?

标签: c#


【解决方案1】:
public object this[string propertyName]
{
    get
    {
        Type myType = typeof(UserConfiguration);
        PropertyInfo myPropInfo = myType.GetProperty(propertyName);
        return myPropInfo.GetValue(this, null);
    }
    set
    {
        Type myType = typeof(UserConfiguration);
        PropertyInfo myPropInfo = myType.GetProperty(propertyName);
        myPropInfo.SetValue(this, value, null);
    }
}

然后您可以使用

获取/设置类中的属性
myClassInstance["ClientId"] = myValue;

【讨论】:

  • 感谢您的回答。我也会试一试,看看它是否能满足我的需求。谢谢你的时间。
【解决方案2】:

如果我明白你的要求,也许这样的事情对你有用:

var argDict = arguments.ToDictionary(x => x.PropertyName, x => x.Value);
Members.ClientID = argDict["ClientID"];
...

如果您需要对键进行一些特殊比较,您可以提供它自己的字典IEqualityComparer。例如,这将确保不区分大小写地处理键:

var argDict = arguments.ToDictionary(x => x.PropertyName, x => x.Value, 
                                     StringComparer.OrdinalIgnoreCase);

只要参数列表包含您需要的所有值,这将正常工作。如果可能缺少某些参数,则必须执行以下操作:

if (argDict.ContainsKey("ClientID")) { 
    Members.ClientID = argDict["ClientID"];
}

或者可能是这样的:

Members.ClientID = argDict.ContainsKey("ClientID") ? argDict["ClientID"] : "DefaultValue";

【讨论】:

  • 感谢 pswg 的回复,让我在我的 OP 中添加一些内容,我确实错过了一些需要回答的重要信息。
  • @DeepToot 是的,这就是我认为你要提出这个问题的地方。基本上,您可以一次将所有参数转换为字典,而不是 foreach 循环 + 开关,然后以有效的方式通过键查找值。
  • 好吧,听起来不错。让我试一试,看看它是否能满足我的需求。感谢您的回复和帮助。
【解决方案3】:

我认为您的基本意图是根据属性名称在目标对象上设置属性的值。由于您没有提供 Argument 类,我假设它是这样定义的:

public class Argument
{
    public string PropertyName{get; set;}
    public object PropertyValue{get;set;}
}

进一步假设您有这样定义的 Blah 类:

public class Blah
{
    public string AString{get; set;}
    public int AnInt{get; set;}
    public DirectoryInfo ADirInfo{get; set;}
}

如果您希望根据List&lt;Argument&gt; 中的值分配给Blah 对象的属性,您可以这样做:

List<Argument> arguments = new List<Argument>
{
    new Argument(){PropertyName = "AString", PropertyValue = "this is a string"},
    new Argument(){PropertyName = "AnInt", PropertyValue = 1729},
    new Argument(){PropertyName = "ADirInfo", PropertyValue = new DirectoryInfo(@"c:\logs")}
};

Blah b = new Blah();
Type blahType = b.GetType();
foreach(Argument arg in arguments)
{
    PropertyInfo prop = blahType.GetProperty(arg.PropertyName);
    // If prop == null then GetProperty() couldn't find a property by that name.  Either it doesn't exist, it's not public, or it's defined on a parent class
    if(prop != null) 
    {
        prop.SetValue(b, arg.PropertyValue);
    }
}

这取决于存储在 Argument.PropertyValue 中的对象与 Argument.PropertyName 引用的 Blah 的属性具有相同类型(或者必须有可用的隐式类型转换)。例如,如果您将List&lt;Argument&gt; 更改如下:

List<Argument> arguments = new List<Argument>
{
    new Argument(){PropertyName = "AString", PropertyValue = "this is a string"},
    new Argument(){PropertyName = "AnInt", PropertyValue = 1729},
    new Argument(){PropertyName = "ADirInfo", PropertyValue = "foo"}
};

您现在在尝试分配给 Blah.ADirInfo 时会遇到异常:Object of type 'System.String' cannot be converted to type 'System.IO.DirectoryInfo'

【讨论】:

  • 在尝试了这些建议中的每一个之后,这一个实际上是为我做的那个。 @p.w.s.g 我很欣赏这个答案,它是正确的,给了我我需要的东西,但是 Odrade 是正确的,让我可以遍历集合并以我需要的方式填充我的类。感谢大家的回复和时间。周末愉快。
猜你喜欢
  • 2021-12-30
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2017-12-04
  • 2013-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多