변환합니다.Null 가능한 유형에서 ChangeType()이 실패함
문자열을 이름이 문자열인 개체 속성 값으로 변환하려고 합니다.저는 이렇게 하려고 노력하고 있습니다.
string modelProperty = "Some Property Name";
string value = "SomeValue";
var property = entity.GetType().GetProperty(modelProperty);
if (property != null) {
property.SetValue(entity,
Convert.ChangeType(value, property.PropertyType), null);
}
문제는 속성 유형이 null일 때 잘못된 캐스트 예외가 발생하고 잘못된 캐스트 예외가 발생한다는 것입니다.값을 변환할 수 없는 경우는 아닙니다. 수동으로 변환하면 값이 작동합니다(예:DateTime? d = Convert.ToDateTime(value);
비슷한 질문을 몇 개 보았지만 여전히 작동하지 않습니다.
테스트되지 않았지만 다음과 같은 방법으로 작동할 수 있습니다.
string modelProperty = "Some Property Name";
string value = "Some Value";
var property = entity.GetType().GetProperty(modelProperty);
if (property != null)
{
Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
object safeValue = (value == null) ? null : Convert.ChangeType(value, t);
property.SetValue(entity, safeValue, null);
}
그렇게 하려면 기본 유형을 알아야 합니다.
이것을 사용해 보십시오. 제네릭에서 성공적으로 사용했습니다.
//Coalesce to get actual property type...
Type t = property.PropertyType();
t = Nullable.GetUnderlyingType(t) ?? t;
//Coalesce to set the safe value using default(t) or the safe type.
safeValue = value == null ? default(t) : Convert.ChangeType(value, t);
코드의 여러 곳에서 사용하는데, 한 가지 예로 데이터베이스 값을 안전한 방식으로 변환하기 위해 사용하는 도우미 메서드가 있습니다.
public static T GetValue<T>(this IDataReader dr, string fieldName)
{
object value = dr[fieldName];
Type t = typeof(T);
t = Nullable.GetUnderlyingType(t) ?? t;
return (value == null || DBNull.Value.Equals(value)) ?
default(T) : (T)Convert.ChangeType(value, t);
}
다음을 사용하여 호출:
string field1 = dr.GetValue<string>("field1");
int? field2 = dr.GetValue<int?>("field2");
DateTime field3 = dr.GetValue<DateTime>("field3");
저는 http://www.endswithsaurus.com/2010_07_01_archive.html 에 이것을 포함한 일련의 블로그 게시물을 썼습니다. (첨부 문서로 스크롤 다운, @John Macintyre는 실제로 제 원래 코드에서 버그를 발견했고, 이 버그는 저를 지금 당신이 가고 있는 것과 같은 길로 이끌었습니다.)저는 그 게시물 이후로 열거형 변환을 포함한 몇 가지 작은 수정 사항이 있습니다. 따라서 당신의 속성이 열거형이라면 여전히 동일한 메서드 호출을 사용할 수 있습니다.열거형을 확인하려면 줄을 추가하기만 하면 다음과 같은 방법을 사용하여 레이스를 시작할 수 있습니다.
if (t.IsEnum)
return (T)Enum.Parse(t, value);
보통 당신은 약간의 오류를 확인하거나 Parse 대신 TryParse를 사용하지만, 당신은 이해할 수 있습니다.
이것은 Nullable 유형에서도 완벽하게 작동합니다.
TypeConverter conv = TypeDescriptor.GetConverter(type);
return conv.ConvertFrom(value);
유형 안전을 위해 전화도 해야 합니다.conv.CanConvertFrom(type)
호출 전 방법ConvertFrom()
거짓으로 반환되는 경우에는 다음으로 되돌아갈 수 있습니다.ChangeType
아니면 다른 것.
예를 들어, 이는 약간 긴 것이지만 비교적 강력한 접근 방식이며 주조 작업을 알 수 없는 값에서 알 수 없는 유형으로 구분합니다.
유사한 작업을 수행하고 null 유형을 고려하는 TryCast 메서드가 있습니다.
public static bool TryCast<T>(this object value, out T result)
{
var type = typeof (T);
// If the type is nullable and the result should be null, set a null value.
if (type.IsNullable() && (value == null || value == DBNull.Value))
{
result = default(T);
return true;
}
// Convert.ChangeType fails on Nullable<T> types. We want to try to cast to the underlying type anyway.
var underlyingType = Nullable.GetUnderlyingType(type) ?? type;
try
{
// Just one edge case you might want to handle.
if (underlyingType == typeof(Guid))
{
if (value is string)
{
value = new Guid(value as string);
}
if (value is byte[])
{
value = new Guid(value as byte[]);
}
result = (T)Convert.ChangeType(value, underlyingType);
return true;
}
result = (T)Convert.ChangeType(value, underlyingType);
return true;
}
catch (Exception ex)
{
result = default(T);
return false;
}
}
물론 TryCast는 유형 매개 변수가 있는 메서드이므로 동적으로 호출하려면 MethodInfo를 직접 구성해야 합니다.
var constructedMethod = typeof (ObjectExtensions)
.GetMethod("TryCast")
.MakeGenericMethod(property.PropertyType);
그런 다음 실제 속성 값을 설정합니다.
public static void SetCastedValue<T>(this PropertyInfo property, T instance, object value)
{
if (property.DeclaringType != typeof(T))
{
throw new ArgumentException("property's declaring type must be equal to typeof(T).");
}
var constructedMethod = typeof (ObjectExtensions)
.GetMethod("TryCast")
.MakeGenericMethod(property.PropertyType);
object valueToSet = null;
var parameters = new[] {value, null};
var tryCastSucceeded = Convert.ToBoolean(constructedMethod.Invoke(null, parameters));
if (tryCastSucceeded)
{
valueToSet = parameters[1];
}
if (!property.CanAssignValue(valueToSet))
{
return;
}
property.SetValue(instance, valueToSet, null);
}
그리고 재산을 처리하기 위한 확장 방법.값을 할당할 수 있음...
public static bool CanAssignValue(this PropertyInfo p, object value)
{
return value == null ? p.IsNullable() : p.PropertyType.IsInstanceOfType(value);
}
public static bool IsNullable(this PropertyInfo p)
{
return p.PropertyType.IsNullable();
}
public static bool IsNullable(this Type t)
{
return !t.IsValueType || Nullable.GetUnderlyingType(t) != null;
}
저도 비슷한 욕구가 있었고, 루크H의 대답은 저를 방향으로 향하게 했습니다.저는 이것을 쉽게 하기 위해 이 일반적인 기능을 생각해냈습니다.
public static Tout CopyValue<Tin, Tout>(Tin from, Tout toPrototype)
{
Type underlyingT = Nullable.GetUnderlyingType(typeof(Tout));
if (underlyingT == null)
{ return (Tout)Convert.ChangeType(from, typeof(Tout)); }
else
{ return (Tout)Convert.ChangeType(from, underlyingT); }
}
용도는 다음과 같습니다.
NotNullableDateProperty = CopyValue(NullableDateProperty, NotNullableDateProperty);
두 번째 매개 변수는 반환 값을 캐스트하는 기능을 보여주는 프로토타입으로 사용되므로 실제로 대상 속성일 필요는 없습니다.즉, 다음과 같은 작업도 수행할 수 있습니다.
DateTime? source = new DateTime(2015, 1, 1);
var dest = CopyValue(source, (string)null);
숙박시설로는 사용할 수 없기 때문에 아웃을 사용하지 않고 이렇게 했습니다.속성과 변수를 사용하여 작업할 수 있습니다.원하는 경우 형식을 전달하기 위해 오버로드를 만들 수도 있습니다.
이런 식으로 했습니다.
public static List<T> Convert<T>(this ExcelWorksheet worksheet) where T : new()
{
var result = new List<T>();
int colCount = worksheet.Dimension.End.Column; //get Column Count
int rowCount = worksheet.Dimension.End.Row;
for (int row = 2; row <= rowCount; row++)
{
var obj = new T();
for (int col = 1; col <= colCount; col++)
{
var value = worksheet.Cells[row, col].Value?.ToString();
PropertyInfo propertyInfo = obj.GetType().GetProperty(worksheet.Cells[1, col].Text);
propertyInfo.SetValue(obj, Convert.ChangeType(value, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType), null);
}
result.Add(obj);
}
return result;
}
@Luke.
는 조금요: 나는조변했니다습금다니▁i.
public static object convertToPropType(PropertyInfo property, object value)
{
object cstVal = null;
if (property != null)
{
Type propType = Nullable.GetUnderlyingType(property.PropertyType);
bool isNullable = (propType != null);
if (!isNullable) { propType = property.PropertyType; }
bool canAttrib = (value != null || isNullable);
if (!canAttrib) { throw new Exception("Cant attrib null on non nullable. "); }
cstVal = (value == null || Convert.IsDBNull(value)) ? null : Convert.ChangeType(value, propType);
}
return cstVal;
}
언급URL : https://stackoverflow.com/questions/3531318/convert-changetype-fails-on-nullable-types
'programing' 카테고리의 다른 글
레일 및 포스트그레SQL: 역할 게시자가 없습니다. (0) | 2023.05.05 |
---|---|
Visual Studio를 사용하여 Azure SQL 백업(.bacpac)을 LocalDB로 가져오는 방법은 무엇입니까? (0) | 2023.05.05 |
SQL Azure의 데이터베이스 간에 쿼리할 수 없음 (0) | 2023.05.05 |
WPF 바인딩에서 값을 null로 설정합니다. (0) | 2023.05.05 |
Bash를 사용하여 표준 출력과 표준 오류를 모두 파일로 리디렉션하고 추가하는 방법 (0) | 2023.05.05 |