DeepToot
DeepToot

Reputation: 79

Best way to assign property value dynamically based on the property name

I have a List that I am iterating through.

Inside the List<> are Argument classes which contain two properties 'PropertyName' and 'Value'

What I need to do is iterate through the collection of Arguments and assign the Value of that Argument to the Property (with the same name as current Argument) of a different class.

Example:

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

I hope this makes sense. I have a way of doing it, hard coding the properties of my class and matching it up with the Argument list.

Something like:

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

But what would the BEST way be for something like this?

EDIT: Sorry about this guys and thanks for the replies so far. Here is what I didn't mention and might make a difference.

Each argument is a different property for the same class. I am iterating through the List and each one in there will be for the same Members class I have to populate.

I wanted to mention this because im thinking in the foreach I might have to use a switch to determine what 'PropertyName' I have for that Argument. ClientID is one of them but I believe there are 14 total properties in the Members class that need populated from the Collection.

Does that change things?

Thanks again

Upvotes: 1

Views: 1805

Answers (3)

Odrade
Odrade

Reputation: 7619

I think that your basic intent is to set the value of a property on a target object based on the property name. Since you did not provide the Argument class I will assume it is defined like this:

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

Further assume you have the class Blah defined like this:

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

If you wish to assign to the properties of a Blah object based on the values in List<Argument> you can do so like this:

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

This depends on the objects stored in Argument.PropertyValue having the same type as the property of Blah referred to by Argument.PropertyName (or there must be an implicit type conversion available). For example, if you alter the List<Argument> as follows:

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

you will now get an exception when attempting to assign to Blah.ADirInfo: Object of type 'System.String' cannot be converted to type 'System.IO.DirectoryInfo'

Upvotes: 0

Mauricio Gracia Gutierrez
Mauricio Gracia Gutierrez

Reputation: 10864

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

Then you can get/set properties within the class using

myClassInstance["ClientId"] = myValue;

Upvotes: 3

p.s.w.g
p.s.w.g

Reputation: 149040

If I understand what you're asking, perhaps something like this will work for you:

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

If you need to do some special comparison on the keys you can provide the dictionary it's own IEqualityComparer. For example, this will make sure that the keys are treated case-insensitively:

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

This will work fine as long as the arguments list contains all the values you need. If some arguments might be missing, you'd have to do something like this:

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

Or possibly something like this:

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

Upvotes: 2

Related Questions