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?

Foi útil?

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:

http: // weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx

A embalagem foi escrito há alguns anos para lidar com isso, mas isso não é perfeito quer.

http: // weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx

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

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;
scroll top