You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何实现对象到匿名类型的转换?求完善ToCast方法

匿名类型与动态对象的自动转换实现

完整扩展方法实现

替换你原代码中ToCast方法的实现,以下是完整的扩展类:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using System.Reflection;

public static class Extensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T value)
    {
        yield return value;
    }

    public static dynamic ToDynamic(this object value)
    {
        IDictionary<string, object> e = new ExpandoObject();
        foreach (PropertyDescriptor item in TypeDescriptor.GetProperties(value.GetType()))
        {
            e.Add(item.Name, item.GetValue(value));
        }
        return e;
    }

    public static IEnumerable<T> ToCast<T>(this IEnumerable<object> value, T sample) where T : class
    {
        if (value == null) yield break;
        var targetType = typeof(T);
        foreach (var item in value)
        {
            yield return item.CastToType(sample);
        }
    }

    public static T ToCastFirstorDefault<T>(this object value, T sample) where T : class
    {
        return value.ToEnumerable().ToCast(sample).Take(1).FirstOrDefault();
    }

    // 核心转换逻辑:将object转换为指定匿名类型
    private static T CastToType<T>(this object source, T sample) where T : class
    {
        if (source == null) return default;
        var sourceType = source.GetType();
        var targetType = typeof(T);
        var targetCtor = targetType.GetConstructors().First();
        var targetParams = targetCtor.GetParameters();
        
        // 匹配属性并转换值
        var paramValues = targetParams.Select(param =>
        {
            var sourceProp = sourceType.GetProperty(param.Name);
            if (sourceProp == null) return param.DefaultValue;
            
            var sourceValue = sourceProp.GetValue(source);
            // 处理集合类型
            if (param.ParameterType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(param.ParameterType))
            {
                var elementType = param.ParameterType.GetGenericArguments()[0];
                // 如果是匿名类型,用示例对象的属性获取元素类型样本
                if (elementType.IsClass && elementType.IsDefined(typeof(CompilerGeneratedAttribute), false))
                {
                    var sampleElement = ((IEnumerable)sample.GetType().GetProperty(param.Name).GetValue(sample))?.Cast<object>().FirstOrDefault();
                    if (sampleElement != null)
                    {
                        var castMethod = typeof(Extensions).GetMethod(nameof(ToCast)).MakeGenericMethod(elementType);
                        return castMethod.Invoke(null, new object[] { ((IEnumerable)sourceValue).Cast<object>(), sampleElement });
                    }
                }
                // 非匿名集合直接转换
                return ((IEnumerable)sourceValue).Cast(elementType);
            }
            // 普通类型直接转换
            return Convert.ChangeType(sourceValue, param.ParameterType);
        }).ToArray();
        
        return (T)targetCtor.Invoke(paramValues);
    }
}

调用示例

按照你期望的方式使用即可:

// 直接转换顶层对象
var rslt = Model.ToCastFirstorDefault(new {
    take = 0,
    data = default(object[])
});

// 嵌套转换集合内的匿名类型
var rsltWithNested = Model.ToCastFirstorDefault(new {
    take = 0,
    data = new[] { new { tarih = default(DateTime), proje = "", durum = false } }
}).ToEnumerable().Select(x => new {
    x.take,
    data = x.data.ToCast(new { tarih = default(DateTime), proje = "", durum = false })
}).Take(1).FirstOrDefault();

实现说明

  1. 核心原理:利用反射获取匿名类型的构造函数与参数信息,匹配源对象的同名属性,递归处理嵌套集合和匿名类型元素。
  2. 集合处理:判断目标类型是否为可枚举类型,如果元素是匿名类型,则通过样本对象获取元素类型,调用泛型ToCast方法完成批量转换。
  3. 为什么不用Convert.ChangeType:匿名类型是编译器自动生成的密封类型,Convert.ChangeType无法处理复杂嵌套结构和匿名类型的实例化,而反射可以直接调用其构造函数,逐个属性赋值转换。

内容的提问来源于stack exchange,提问作者Uğur Demirel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:20:42