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

寻求非空值对象属性赋值的通用方法(C#场景)

替代逐个if判断的属性赋值优化方案

场景说明:给新创建的对象属性赋值时,仅当第三方提供的待赋值变量通过多维度空值校验(涵盖null、空字符串、空白字符、无效日期等,不同第三方校验逻辑存在差异)时,才覆盖对象默认值。当前实现为逐个属性编写if判断,希望简化调用逻辑,通过传入对象、属性、待赋值变量的方式完成按需赋值。

方案1:通用赋值方法+自定义空值校验器

先定义空值校验接口,针对不同第三方实现专属校验逻辑:

public interface INullChecker
{
    bool IsNullOrInvalid(object value);
}

// 示例:第三方A的校验器
public class ThirdPartyAChecker : INullChecker
{
    public bool IsNullOrInvalid(object value)
    {
        if (value == null) return true;
        if (value is string str) return string.IsNullOrWhiteSpace(str);
        if (value is DateTime dt) return dt == DateTime.MinValue;
        return false;
    }
}

// 其他第三方校验器可按相同逻辑实现

再编写通用赋值方法,通过表达式树定位属性,避免硬编码:

public static void AssignIfValid<T, TProp>(T target, Expression<Func<T, TProp>> propertyExpr, TProp newValue, INullChecker checker)
{
    if (checker.IsNullOrInvalid(newValue)) return;
    
    var property = (PropertyInfo)((MemberExpression)propertyExpr.Body).Member;
    property.SetValue(target, newValue);
}

调用示例:

var bar = newFoo();
var checker = new ThirdPartyAChecker(); // 根据当前数据源选择对应校验器

AssignIfValid(bar, x => x.ID, newID, checker);
AssignIfValid(bar, x => x.Name, newName, checker);
AssignIfValid(bar, x => x.OpenDate, newOpenDate, checker);

该方案优势:

  • 统一赋值逻辑,避免重复编写if判断
  • 第三方校验逻辑封装到单独类中,符合单一职责原则
  • 调用语法简洁,意图清晰

方案2:扩展方法增强可读性

将通用赋值方法改为扩展方法,让调用更自然:

public static class ObjectExtensions
{
    public static void AssignIfValid<T, TProp>(this T target, Expression<Func<T, TProp>> propertyExpr, TProp newValue, INullChecker checker)
    {
        if (checker.IsNullOrInvalid(newValue)) return;
        
        var property = (PropertyInfo)((MemberExpression)propertyExpr.Body).Member;
        property.SetValue(target, newValue);
    }
}

调用示例:

var bar = newFoo();
var checker = new ThirdPartyAChecker();

bar.AssignIfValid(x => x.ID, newID, checker);
bar.AssignIfValid(x => x.Name, newName, checker);
bar.AssignIfValid(x => x.OpenDate, newOpenDate, checker);

方案3:批量赋值(适用于属性与第三方值有固定映射的场景)

若第三方字段与内部类属性存在固定对应关系,可通过反射+映射字典批量处理,减少重复代码:

public static void BatchAssign<T>(T target, Dictionary<string, object> thirdPartyValues, INullChecker checker)
{
    var type = typeof(T);
    foreach (var kvp in thirdPartyValues)
    {
        var property = type.GetProperty(kvp.Key);
        if (property == null) continue;
        
        if (checker.IsNullOrInvalid(kvp.Value)) continue;
        
        // 可根据需求添加类型转换逻辑,比如string转int等
        var convertedValue = Convert.ChangeType(kvp.Value, property.PropertyType);
        property.SetValue(target, convertedValue);
    }
}

调用示例:

var bar = newFoo();
var thirdPartyData = new Dictionary<string, object>
{
    { nameof(Foo.ID), newID },
    { nameof(Foo.Name), newName },
    { nameof(Foo.OpenDate), newOpenDate }
};
var checker = new ThirdPartyAChecker();

BatchAssign(bar, thirdPartyData, checker);

该方案适合属性数量较多的场景,一次性处理所有属性,但需维护字段映射关系,类型转换需额外处理。

与原生if语句的对比

  • 原生if语句:性能最优,无反射/表达式树开销;但代码冗余,属性数量多时需编写大量重复逻辑,后期维护成本高。
  • 上述方案:代码简洁,维护性强,校验逻辑统一管理;存在轻微反射性能开销(属性数量在100以内时可忽略)。

若属性数量最多100个且无极端性能要求,方案1或2为更优选择;若性能为首要考量,原生if语句也可接受,虽冗余但稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 08:13:14