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
相关产品推荐
相关产品推荐

