문자열 값으로 리플렉션하여 속성 설정


312

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
질문 : 맞춤형 ORM 솔루션의 일부입니까?
user3308043 2016 년

답변:


527

당신은 사용할 수 있습니다 Convert.ChangeType()-그것은 당신이 어떤 런타임 정보를 사용할 수 있습니다IConvertible 유형의 하여 표시 형식을 변경할 수 있습니다. 그러나 모든 변환이 가능한 것은 아니며, 그렇지 않은 유형의 변환을 지원하려면 특수한 경우 논리를 작성해야 할 수도 있습니다 IConvertible.

해당 코드 (예외 처리 또는 특수 사례 논리 제외)는 다음과 같습니다.

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);

아래 @AliKaraca 답변을 검토하십시오. 이것과 아래의 것은 빠르지 만 느슨하지만 일반적인 유형의 작업을 수행합니다.
Aaron Hudon

있는가 TryChangeType또는 CanChangeType?
Shimmy Weitzhandler

34

다른 사람들이 말했듯이 다음을 사용하고 싶습니다 Convert.ChangeType.

propertyInfo.SetValue(ship,
    Convert.ChangeType(value, propertyInfo.PropertyType),
    null);

사실, 나는 전체 ConvertClass 를 보는 것이 좋습니다 .

이 클래스와 다른 많은 유용한 클래스는 System네임 스페이스의 일부입니다 . 매년 해당 네임 스페이스를 스캔하여 놓친 기능을 확인하는 것이 유용하다는 것을 알았습니다. 시도 해봐!


1
OP는 아마도 문자열에서 명백하게 변환되는 모든 유형의 속성을 설정하기 위해 일반적인 대답을 원할 것입니다.
Daniel Earwicker

좋은 지적. 나는 실제 응답자를 편집하고 가리 키거나 누군가가 네임 스페이스의 나머지 부분에 대해 말한 것을 추가하면 광산을 삭제합니다.
John Saunders

19

많은 사람들이 추천하고 있음을 알았습니다 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


13

LBushkin 에서 답을 시도했지만 훌륭하게 작동했지만 null 값과 nullable 필드에는 작동하지 않습니다. 그래서 이것을 다음과 같이 변경했습니다.

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

이 사례를 만났을 때 감사하다고 말해야하며 이것이 유일한 해결책입니다. 고마워 ~!
Franva

11

유형 변환기를 사용할 수 있습니다 (오류 검사 없음).

Ship ship = new Ship();
string value = "5.5";
var property = ship.GetType().GetProperty("Latitude");
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);

코드 구성 측면 에서 다음과 같은 코드를 생성하는 일종의 믹스 인 을 만들 수 있습니다 .

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 { ... }

마커를 사용하는 대신 마커 insterface를 추가 한 특별한 이유가 object있습니까?
Groo

1
예, 마커 인터페이스는 확장 메소드를 추가 할 자리 표시 자 역할을합니다. 를 사용하면 object모든 클래스에 확장 메소드를 추가 할 수 있지만 일반적으로 바람직하지 않습니다.
Jordão

6

아마도 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);

5

사용 Convert.ChangeType하고 변환하는 유형을 받고 PropertyInfo.PropertyType.

propertyInfo.SetValue( ship,
                       Convert.ChangeType( value, propertyInfo.PropertyType ),
                       null );

4

나는 일반적인 대답으로 이것에 대답 할 것이다. 일반적으로 이러한 답변은 guid와 작동하지 않습니다. 다음은 guid가있는 작동 버전입니다.

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

1
이것은 정답입니다. GUID <3에서도 작동합니다. 감사합니다, 알리 (제 딸의 별명입니다)
Cătălin Rădoi

3

또는 시도해 볼 수 있습니다.

propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);

//But this will cause problems if your string value IsNullOrEmplty...

2

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

0

다음 코드를 사용하면 문제가 해결됩니다.

item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));

-9

리플렉션을 사용하거나 소프트웨어 제작을 원하십니까? 왜 반사를 사용하여 속성을 설정하는지 궁금합니다.

Double new_latitude;

Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;

1
사람들이해야 할 일을 존중해야하며 사람들이해야 할 일을 존중해서는 안됩니다. 공감. (보낸 사람 GenericProgramming.exe:ReflectionBenefits())
Петър Петров
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.