Установка свойства путем отражения со строковым значением
Я хотел бы установить свойство объекта через Reflection со значением типа string
.
Например, предположим, что у меня есть класс Ship
с свойством Latitude
, который является double
.
Вот что я хотел бы сделать:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, value, null);
Как и в случае, это выбрасывает ArgumentException
:
Объект типа "System.String" не может быть преобразован в тип "System.Double".
Как я могу преобразовать значение в правильный тип на основе propertyInfo
?
Ответы
Ответ 1
Вы можете использовать Convert.ChangeType()
- он позволяет вам использовать информацию о времени выполнения для любого типа IConvertible
для изменения форматов представления. Однако не все преобразования возможны, и вам может потребоваться написать специальную логику case, если вы хотите поддерживать преобразования из типов, которые не являются IConvertible
.
Соответствующий код (без обработки исключений или логика конкретного случая) будет:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Ответ 2
Как уже говорили некоторые другие, вы хотите использовать Convert.ChangeType
:
propertyInfo.SetValue(ship,
Convert.ChangeType(value, propertyInfo.PropertyType),
null);
На самом деле, я рекомендую вам посмотреть весь Convert
класс.
Этот класс и многие другие полезные классы являются частью System
Namespace. Мне посчастливилось сканировать это пространство имен каждый год или около того, чтобы увидеть, какие функции я пропустил. Попробуйте!
Ответ 3
Я замечаю, что многие рекомендуют Convert.ChangeType
- это работает в некоторых случаях, однако, как только вы начнете включать типы nullable
, вы начнете получать InvalidCastExceptions
:
http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx
Несколько лет назад была написана обертка, чтобы справиться с этим, но это тоже не идеально.
http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx
Ответ 4
Вы можете использовать конвертер типов (без проверки ошибок):
Ship ship = new Ship();
string value = "5.5";
var property = ship.GetType().GetProperty("Latitude");
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);
В плане организации кода вы можете создать вид mixin, который приведет к следующему коду:
Ship ship = new Ship();
ship.SetPropertyAsString("Latitude", "5.5");
Это будет достигнуто с помощью этого кода:
public interface MPropertyAsStringSettable { }
public static class PropertyAsStringSettable {
public static void SetPropertyAsString(
this MPropertyAsStringSettable self, string propertyName, string value) {
var property = TypeDescriptor.GetProperties(self)[propertyName];
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);
}
}
public class Ship : MPropertyAsStringSettable {
public double Latitude { get; set; }
// ...
}
MPropertyAsStringSettable
может быть повторно использован для разных классов.
Вы также можете создать свой собственный тип преобразователей для присоединения к вашим свойствам или классам:
public class Ship : MPropertyAsStringSettable {
public Latitude Latitude { get; set; }
// ...
}
[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
Ответ 5
Вероятно, вы ищете метод Convert.ChangeType
. Например:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Ответ 6
Использование Convert.ChangeType
и получение типа для преобразования из PropertyInfo.PropertyType
.
propertyInfo.SetValue( ship,
Convert.ChangeType( value, propertyInfo.PropertyType ),
null );
Ответ 7
Или вы могли бы попробовать:
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
//But this will cause problems if your string value IsNullOrEmplty...
Ответ 8
Если вы пишете приложение Metro, вы должны использовать другой код:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType));
Примечание:
ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
вместо
ship.GetType().GetProperty("Latitude");
Ответ 9
Я попробовал ответ от LBushkin, и он отлично поработал, но он не будет работать для нулевых значений и полей с нулевым значением. Поэтому я изменил его на следующее:
propertyName= "Latitude";
PropertyInfo propertyInfo = ship.GetType().GetProperty(propertyName);
if (propertyInfo != null)
{
Type t = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
object safeValue = (value == null) ? null : Convert.ChangeType(value, t);
propertyInfo.SetValue(ship, safeValue, null);
}
Ответ 10
Вы хотите поиграть с Reflection или хотите создать производственную часть программного обеспечения? Я бы поставил под вопрос, почему вы используете отражение, чтобы установить свойство.
Double new_latitude;
Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;