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

在C# .NET Framework 4.8中动态定义类的可变数量列属性

在.NET Framework 4.8中动态生成NodeN类的列属性及适配构造函数

完全可行,以下是几种适配场景的实用实现方案:

方案1:基于DynamicObject实现动态属性访问

这种方式无需预定义固定属性,通过重写DynamicObject的核心方法,让类支持动态属性的读写,构造函数可接收可变数量的参数完成列初始化。

using System.Dynamic;
using System.Collections.Generic;

public class NodeN : DynamicObject
{
    private readonly Dictionary<string, object> _columns = new Dictionary<string, object>();
    public int NumberOfColumns { get; }

    // 构造函数:接收列数 + 对应数量的列值参数
    public NodeN(int numberOfColumns, params object[] columnValues)
    {
        NumberOfColumns = numberOfColumns;
        if (columnValues.Length != numberOfColumns)
            throw new ArgumentException($"必须传入{numberOfColumns}个列值参数");

        for (int i = 0; i < numberOfColumns; i++)
        {
            _columns[$"Column{i+1}"] = columnValues[i];
        }
    }

    // 重写获取属性的逻辑
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return _columns.TryGetValue(binder.Name, out result);
    }

    // 重写设置属性的逻辑
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (binder.Name.StartsWith("Column") && int.TryParse(binder.Name.Substring(6), out int index) 
            && index >=1 && index <= NumberOfColumns)
        {
            _columns[binder.Name] = value;
            return true;
        }
        return false;
    }
}

使用示例:

dynamic node = new NodeN(3, "第一列", 100, DateTime.Now);
// 读取动态属性
var col1 = node.Column1;
var col2 = node.Column2;
// 设置动态属性
node.Column3 = "更新后的值";

优缺点:实现简单灵活,适配任意列数;但依赖dynamic关键字,无编译时类型检查,IDE无智能提示。

方案2:通过反射Emit动态生成强类型类

如果需要强类型支持(编译时检查、IDE智能提示),可在运行时通过Reflection.Emit动态生成包含指定数量Column属性的类,同时生成匹配的构造函数。

using System.Reflection;
using System.Reflection.Emit;

public static class NodeNGenerator
{
    public static Type GenerateNodeType(int numberOfColumns)
    {
        // 定义动态程序集与模块
        var assemblyName = new AssemblyName($"DynamicNodeAssembly_{numberOfColumns}");
        var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicNodeModule");

        // 定义动态类
        var typeBuilder = moduleBuilder.DefineType($"NodeN_{numberOfColumns}", TypeAttributes.Public);
        var fields = new FieldBuilder[numberOfColumns];

        // 生成Column1到ColumnN的属性和私有字段
        for (int i = 0; i < numberOfColumns; i++)
        {
            string propName = $"Column{i+1}";
            var fieldBuilder = typeBuilder.DefineField($"_{propName}", typeof(object), FieldAttributes.Private);
            fields[i] = fieldBuilder;

            var propBuilder = typeBuilder.DefineProperty(propName, PropertyAttributes.None, typeof(object), null);
            // 生成属性get方法
            var getMethod = typeBuilder.DefineMethod($"get_{propName}", MethodAttributes.Public | MethodAttributes.SpecialName, typeof(object), Type.EmptyTypes);
            var getIl = getMethod.GetILGenerator();
            getIl.Emit(OpCodes.Ldarg_0);
            getIl.Emit(OpCodes.Ldfld, fieldBuilder);
            getIl.Emit(OpCodes.Ret);
            // 生成属性set方法
            var setMethod = typeBuilder.DefineMethod($"set_{propName}", MethodAttributes.Public | MethodAttributes.SpecialName, typeof(void), new[] { typeof(object) });
            var setIl = setMethod.GetILGenerator();
            setIl.Emit(OpCodes.Ldarg_0);
            setIl.Emit(OpCodes.Ldarg_1);
            setIl.Emit(OpCodes.Stfld, fieldBuilder);
            setIl.Emit(OpCodes.Ret);

            propBuilder.SetGetMethod(getMethod);
            propBuilder.SetSetMethod(setMethod);
        }

        // 生成匹配列数的构造函数
        var ctorParams = new Type[numberOfColumns];
        Array.Fill(ctorParams, typeof(object));
        var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctorParams);
        var ctorIl = ctorBuilder.GetILGenerator();

        // 构造函数逻辑:将参数赋值给对应字段
        for (int i = 0; i < numberOfColumns; i++)
        {
            ctorIl.Emit(OpCodes.Ldarg_0);
            ctorIl.Emit(OpCodes.Ldarg, i+1);
            ctorIl.Emit(OpCodes.Stfld, fields[i]);
        }
        ctorIl.Emit(OpCodes.Ret);

        return typeBuilder.CreateType();
    }
}

使用示例:

// 生成包含3个列的强类型Node类
Type nodeType = NodeNGenerator.GenerateNodeType(3);
// 实例化对象并传入初始化参数
object node = Activator.CreateInstance(nodeType, "列1", 200, DateTime.Now);
// 通过反射访问属性
var col1Value = nodeType.GetProperty("Column1").GetValue(node);

优缺点:拥有强类型特性,支持编译时检查(可提前缓存生成的类型);但实现复杂,反射操作性能略低,IDE智能提示需提前生成类型。

方案3:字典+索引器模拟动态属性

如果不想依赖dynamic或反射,可直接用字典存储列值,通过索引器模拟属性访问,构造函数同样支持可变参数。

using System.Collections.Generic;

public class NodeN
{
    private readonly Dictionary<int, object> _columns = new Dictionary<int, object>();
    public int NumberOfColumns { get; }

    public NodeN(int numberOfColumns, params object[] columnValues)
    {
        NumberOfColumns = numberOfColumns;
        if (columnValues.Length != numberOfColumns)
            throw new ArgumentException($"必须传入{numberOfColumns}个列值参数");

        for (int i = 0; i < numberOfColumns; i++)
        {
            _columns[i+1] = columnValues[i];
        }
    }

    // 索引器:通过数字访问列,如node[1]对应Column1
    public object this[int columnIndex]
    {
        get
        {
            if (columnIndex <1 || columnIndex > NumberOfColumns)
                throw new IndexOutOfRangeException("列索引超出范围");
            return _columns[columnIndex];
        }
        set
        {
            if (columnIndex <1 || columnIndex > NumberOfColumns)
                throw new IndexOutOfRangeException("列索引超出范围");
            _columns[columnIndex] = value;
        }
    }

    // 可选:通过属性名称访问的方法
    public object GetColumn(string columnName)
    {
        if (columnName.StartsWith("Column") && int.TryParse(columnName.Substring(6), out int index)
            && index >=1 && index <= NumberOfColumns)
        {
            return _columns[index];
        }
        throw new ArgumentException("无效的列名称");
    }

    public void SetColumn(string columnName, object value)
    {
        if (columnName.StartsWith("Column") && int.TryParse(columnName.Substring(6), out int index)
            && index >=1 && index <= NumberOfColumns)
        {
            _columns[index] = value;
            return;
        }
        throw new ArgumentException("无效的列名称");
    }
}

使用示例:

var node = new NodeN(2, "测试值", 300);
// 通过索引器访问
var col1 = node[1];
node[2] = "更新值";
// 通过方法访问
var col2 = node.GetColumn("Column2");
node.SetColumn("Column1", "新值");

优缺点:实现简单、类型安全,无dynamic依赖;但没有直接的属性访问语法,需通过索引器或方法操作。

内容的提问来源于stack exchange,提问作者ng80092b

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 12:16:08