Definir uma propriedade por reflexão com um valor de string
-
23-08-2019 - |
Pergunta
Eu gostaria de definir uma propriedade de um objeto através da reflexão, com um valor de tipo string
.
Assim, por exemplo, suponha que eu tenho uma classe Ship
, com uma propriedade de Latitude
, que é um double
.
Aqui está o que eu gostaria de fazer:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, value, null);
Como é que isso gera uma ArgumentException
:
Objeto do tipo 'System' não pode ser convertido para o tipo 'System.Double'.
Como posso converter o valor para o tipo apropriado, com base em propertyInfo
?
Solução
Você pode usar Convert.ChangeType()
- Ele permite que você use as informações de tempo de execução em qualquer tipo IConvertible
para alterar os formatos de representação. Nem todas as conversões são possíveis, embora, e você pode precisar de escrever lógica caso especial se você quiser apoiar conversões de tipos que não são IConvertible
.
O código correspondente (sem tratamento de exceção ou a lógica caso especial) seria:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Outras dicas
Como vários outros já disseram, você quer usar Convert.ChangeType
:
propertyInfo.SetValue(ship,
Convert.ChangeType(value, propertyInfo.PropertyType),
null);
Na verdade, eu recomendo que você olhar para o todo Convert
Class .
Esta classe, e muitas outras classes úteis são parte do System
Namespace . Acho que é útil para verificar que namespace cada ano ou assim para ver quais as características que eu perdi. Experimentá-lo!
Eu noto que muitas pessoas estão recomendando Convert.ChangeType
- Isto funciona para alguns casos, no entanto, logo que você começar a envolver tipos nullable
você vai começar a receber InvalidCastExceptions
:
A embalagem foi escrito há alguns anos para lidar com isso, mas isso não é perfeito quer.
Você pode usar um conversor de tipo (sem verificação de erros):
Ship ship = new Ship();
string value = "5.5";
var property = ship.GetType().GetProperty("Latitude");
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);
Em termos de organização do código, você poderia criar um tipo-de mixin que resultaria em um código como este:
Ship ship = new Ship();
ship.SetPropertyAsString("Latitude", "5.5");
Este seria alcançado com este código:
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
pode ser reutilizado para muitas classes diferentes.
Você também pode criar seu próprio costume tipo conversores para anexar às suas propriedades ou classes:
public class Ship : MPropertyAsStringSettable {
public Latitude Latitude { get; set; }
// ...
}
[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
Eu tentei a resposta de LBushkin e funcionou muito bem, mas não vai funcionar para valores nulos e campos anuláveis. Então eu mudei-o para isto:
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);
}
Você está procurando provavelmente o href="http://msdn.microsoft.com/en-us/library/dtb69x08.aspx" rel="noreferrer"> Convert.ChangeType
método . Por exemplo:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Usando Convert.ChangeType
e obter o tipo para converter a partir do PropertyInfo.PropertyType
.
propertyInfo.SetValue( ship,
Convert.ChangeType( value, propertyInfo.PropertyType ),
null );
Eu vou responder isso com uma resposta geral. Normalmente, estas respostas não trabalhar com guids. Aqui está uma versão de trabalho com guids também.
var stringVal="6e3ba183-89d9-e611-80c2-00155dcfb231"; // guid value as string to set
var prop = obj.GetType().GetProperty("FooGuidProperty"); // property to be setted
var propType = prop.PropertyType;
// var will be type of guid here
var valWithRealType = TypeDescriptor.GetConverter(propType).ConvertFrom(stringVal);
Ou você pode tentar:
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
//But this will cause problems if your string value IsNullOrEmplty...
Se você estiver escrevendo aplicativo Metro, você deve usar outro código:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType));
Nota:
ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
em vez de
ship.GetType().GetProperty("Latitude");
Usando o seguinte código deve resolver o seu problema:
item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));
Você está olhando para brincar com reflexão ou você está olhando para construir uma peça produção de software? Eu gostaria de questionar por que você está usando a reflexão para definir uma propriedade.
Double new_latitude;
Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;