首页 新闻 会员 周边 捐助

创建一个SetPropertyCalls映射表达式 SetProperty 方法始终无法匹配

0
悬赏园豆:20 [待解决问题]

/// <summary>
///创建一个映射表达式
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TDest"></typeparam>
/// <param name="dest"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="InvalidOperationException"></exception>
public static Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>>
CreateSetPropertyExpression<TEntity, TDest>(TDest dest)
{
if (dest == null)
{
throw new ArgumentNullException(nameof(dest));
}

ParameterExpression settersParameter = Expression.Parameter(typeof(SetPropertyCalls<TEntity>), "setters");
Type entityType = typeof(TEntity);
Type destType = typeof(TDest);

// 匿名类型的特殊处理:获取所有实例属性(包括只读属性)
PropertyInfo[] destProperties = destType.GetProperties(BindingFlags.Instance | BindingFlags.Public);

Expression currentExpression = settersParameter;
bool hasValidProperties = false;

foreach (PropertyInfo destProperty in destProperties)
{
// 跳过索引器属性(匿名类型不会包含)
if (destProperty.GetIndexParameters().Length > 0)
{
continue;
}

// 查找实体类中同名且可写的属性
PropertyInfo? entityProperty = entityType.GetProperty(
destProperty.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase // 支持不区分大小写
);

if (entityProperty == null || !entityProperty.CanWrite)
{
continue;
}

// 获取匿名对象的属性值
object? destValue = destProperty.GetValue(dest);

// 处理类型转换(包括可空类型)
Type targetType = entityProperty.PropertyType;
try
{
destValue = ConvertValue(destValue, targetType);
}
catch (InvalidCastException ex)
{
throw new InvalidOperationException(
$"属性 {destProperty.Name} 类型转换失败: {ex.Message}", ex);
}

// 构建属性设置表达式
ParameterExpression entityParam = Expression.Parameter(entityType, "e");
MemberExpression propertyAccess = Expression.Property(entityParam, entityProperty);
LambdaExpression selector = Expression.Lambda(propertyAccess, entityParam);

// 创建常量表达式(支持null值)
ConstantExpression valueExpr = Expression.Constant(destValue, targetType);

// 获取泛型SetProperty方法
// 查找 SetProperty 方法
MethodInfo? setPropertyMethod = typeof(SetPropertyCalls<TEntity>).GetMethods().Where(d => d.Name == "SetProperty").ToArray()[1]?
.MakeGenericMethod(typeof(Func<,>).MakeGenericType(entityType, targetType), targetType) ?? throw new InvalidOperationException("setPropertyMethod 失败");
// 链式调用构建
currentExpression = Expression.Call(
currentExpression,
setPropertyMethod,
selector,
valueExpr
);

hasValidProperties = true;
}

return !hasValidProperties
? throw new InvalidOperationException("未找到可映射的属性")
: Expression.Lambda<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>>(
currentExpression,
settersParameter
);
}

private static object? ConvertValue(object? value, Type targetType)
{
if (value == null)
{
return targetType.IsValueType && !IsNullableType(targetType)
? throw new InvalidCastException($"无法将null赋值给非可空类型 {targetType}")
: null;
}

Type sourceType = value.GetType();
Type underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType;

// 类型直接匹配
if (underlyingTargetType.IsAssignableFrom(sourceType))
{
return value;
}

// 处理数值类型转换(如int到long)
return IsNumericType(sourceType) && IsNumericType(underlyingTargetType)
? Convert.ChangeType(value, underlyingTargetType)
: throw new InvalidCastException($"无法将类型 {sourceType} 转换为 {targetType}");
}

private static bool IsNullableType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}

private static bool IsNumericType(Type type)
{
Type[] numericTypes = {
typeof(int), typeof(double), typeof(decimal),
typeof(long), typeof(short), typeof(float),
typeof(byte), typeof(uint), typeof(ulong),
typeof(ushort), typeof(sbyte)
};
return Array.Exists(numericTypes, t => t == type);
}

SpeakHero的主页 SpeakHero | 初学一级 | 园豆:13
提问于:2025-03-03 15:49
< >
分享
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册