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


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.