Действительно ли возможно передать на имя свойства как строка и присвоить значение ему?

Я настраиваю простой класс помощника для содержания некоторых данных из файла, который я анализирую. Названия свойств соответствуют названиям значений, которые я ожидаю находить в файле. Я хотел бы добавить названный метод AddPropertyValue к моему классу так, чтобы я мог присвоить значение свойству, явно не зовя его по имени.

Метод был бы похож на это:

//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

Реализация могла бы быть похожей на это:

C#/VB.NET

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

Это возможное, не имея необходимость тестировать на каждое отдельное имя свойства против предоставленного propertyName?

6
задан Ben McCormack 9 August 2010 в 18:51
поделиться

3 ответа

Вы можете сделать это с помощью отражения, вызвав Type.GetProperty , а затем PropertyInfo.SetValue . Вам нужно будет выполнить соответствующую обработку ошибок, чтобы проверить, действительно ли свойство отсутствует.

Вот пример:

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

Если вам нужно делать это много, это может стать проблемой с точки зрения производительности. Есть уловки с делегатами, которые могут сделать это намного быстрее, но сначала стоит заставить его работать.

7
ответ дан 8 December 2019 в 18:29
поделиться

Используя отражение, вы получаете свойство по имени и устанавливаете его значение... что-то вроде:

Type t = this.GetType();
var prop = t.GetProperty(propName);
prop.SetValue(this, value, null);
4
ответ дан 8 December 2019 в 18:29
поделиться

С точки зрения организации кода, вы можете сделать это миксиноподобным способом (отдельно от обработки ошибок):

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

Таким образом, вы можете повторно использовать эту логику во многих разных классах, не жертвуя вместе с ним вашим драгоценным единственным базовым классом.

В 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
2
ответ дан 8 December 2019 в 18:29
поделиться