Is it possible to pass in a property name as a str

2020-03-21 10:06发布

问题:

I'm setting up a simple helper class to hold some data from a file I'm parsing. The names of the properties match the names of values that I expect to find in the file. I'd like to add a method called AddPropertyValue to my class so that I can assign a value to a property without explicitly calling it by name.

The method would look like this:

//C#
public void AddPropertyValue(string propertyName, string propertyValue) {
   //code to assign the property value based on propertyName
}

---

'VB.NET'
Public Sub AddPropertyValue(ByVal propertyName As String, _
                            ByVal propertyValue As String)
    'code to assign the property value based on propertyName '
End Sub

The implementation might look like this:

C#/VB.NET

MyHelperClass.AddPropertyValue("LocationID","5")

Is this possible without having to test for each individual property name against the supplied propertyName?

回答1:

You can do this with reflection, by calling Type.GetProperty and then PropertyInfo.SetValue. You'll need to do appropriate error handling to check for the property not actually being present though.

Here's a sample:

using System;
using System.Reflection;

public class Test
{
    public string Foo { get; set; }
    public string Bar { get; set; }

    public void AddPropertyValue(string name, string value)
    {
        PropertyInfo property = typeof(Test).GetProperty(name);
        if (property == null)
        {
            throw new ArgumentException("No such property!");
        }
        // More error checking here, around indexer parameters, property type,
        // whether it's read-only etc
        property.SetValue(this, value, null);
    }

    static void Main()
    {
        Test t = new Test();
        t.AddPropertyValue("Foo", "hello");
        t.AddPropertyValue("Bar", "world");

        Console.WriteLine("{0} {1}", t.Foo, t.Bar);
    }
}

If you need to do this a lot, it can become quite a pain in terms of performance. There are tricks around delegates which can make it a lot faster, but it's worth getting it working first.



回答2:

Using reflection you get the property using the name and set its value... something like:

Type t = this.GetType();
var prop = t.GetProperty(propName);
prop.SetValue(this, value, null);


回答3:

In terms of organizing the code, you could do it in a mixin-like way (error handling apart):

public interface MPropertySettable { }
public static class PropertySettable {
  public static void SetValue<T>(this MPropertySettable self, string name, T value) {
    self.GetType().GetProperty(name).SetValue(self, value, null);
  }
}
public class Foo : MPropertySettable {
  public string Bar { get; set; }
  public int Baz { get; set; }
}

class Program {
  static void Main() {
    var foo = new Foo();
    foo.SetValue("Bar", "And the answer is");
    foo.SetValue("Baz", 42);
    Console.WriteLine("{0} {1}", foo.Bar, foo.Baz);
  }
}

This way, you can reuse that logic in many different classes, without sacrificing your precious single base class with it.

In VB.NET:

Public Interface MPropertySettable
End Interface
Public Module PropertySettable
  <Extension()> _
  Public Sub SetValue(Of T)(ByVal self As MPropertySettable, ByVal name As String, ByVal value As T)
    self.GetType().GetProperty(name).SetValue(self, value, Nothing)
  End Sub
End Module