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
?
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.
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);
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