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

C#中如何像传递枚举一样传递泛型类型的属性?

解决方案

方案1:用表达式树实现强类型属性传递

这是最直接的实现方式,既能自动提取属性名,又能保证值的类型安全,完全不用额外定义枚举或元数据类。

先定义泛型的Update方法:

using System.Linq.Expressions;

void Update<T>(long id, Expression<Func<TodoItem, T>> propertySelector, T value)
{
    // 从表达式里解析出属性名
    var memberExpr = propertySelector.Body as MemberExpression;
    string propertyName = memberExpr.Member.Name;

    // 重点:必须用参数化查询防SQL注入,绝对不能直接拼值到SQL里
    string sql = $"UPDATE tablename SET {propertyName} = @value WHERE id = @id";
    
    // 执行SQL的示例(用参数化)
    using var cmd = new SQLiteCommand(sql, connection);
    cmd.Parameters.AddWithValue("@value", value ?? DBNull.Value);
    cmd.Parameters.AddWithValue("@id", id);
    cmd.ExecuteNonQuery();
}

然后在ViewModel的属性setter里这么调用:

public string Description
{
    get => _description;
    set
    {
        this.RaiseAndSetIfChanged(ref _description, value);
        Update(Id, item => item.Description, value);
    }
}

public DateTime? DueDate
{
    get => _dueDate;
    set
    {
        this.RaiseAndSetIfChanged(ref _dueDate, value);
        Update(Id, item => item.DueDate, value);
    }
}

这个方案的好处:

  • 编译时就能检查值的类型是否匹配,不会出现传错类型的情况
  • 不需要硬编码属性名,避免拼写错误
  • 写法简洁,没有额外的冗余代码

方案2:预定义属性元数据类(接近枚举式调用)

如果你更倾向于像用枚举一样传递属性,可以给TodoItem做一个静态元数据类,把每个属性的信息封装起来:

public static class TodoItemProperties
{
    public static readonly PropertyMetadata<string> Description = new(nameof(TodoItem.Description));
    public static readonly PropertyMetadata<DateTime?> DueDate = new(nameof(TodoItem.DueDate));
    public static readonly PropertyMetadata<bool> IsFinished = new(nameof(TodoItem.IsFinished));

    public class PropertyMetadata<T>
    {
        public string PropertyName { get; }

        public PropertyMetadata(string propertyName)
        {
            PropertyName = propertyName;
        }
    }
}

对应的Update方法改成:

void Update<T>(long id, TodoItemProperties.PropertyMetadata<T> property, T value)
{
    string sql = $"UPDATE tablename SET {property.PropertyName} = @value WHERE id = @id";
    // 同样用参数化执行SQL...
}

ViewModel里的调用就像用枚举一样:

public string Description
{
    get => _description;
    set
    {
        this.RaiseAndSetIfChanged(ref _description, value);
        Update(Id, TodoItemProperties.Description, value);
    }
}

这个方案的好处:

  • 调用语义更清晰,一眼就能看出是更新哪个属性
  • 属性名只需要硬编码一次,集中管理,方便维护
  • 同样是强类型,编译时就能校验值的类型

必须注意的点

  • 无论用哪种方案,绝对不能直接把值拼进SQL字符串,一定要用参数化查询,否则会有严重的SQL注入风险。
  • 处理可空类型(比如DateTime?)时,要把null转换成DBNull.Value再传入SQL参数,避免数据库报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 13:36:38