将get / set属性作为参数传递而不进行反射的最佳方法

时间:2016-05-31 15:20:36

标签: c# properties

有时,在处理数据传输对象(例如从数据库或csv文件中检索)时,编写一些辅助函数来移动数据会很不错。

例如:

class MyDto
{
    public string Name { get; set; }
}

class MyBusinessObject
{
    public string Name { get; set;}
}

我想写一些类似的东西:

MyDto source;
MyBusinessObject target;

var hasChanged = target.Set(source, source => source.Name, target => target.Name); // lamdba expressions, or whatever it takes to make it work

使用扩展方法:

public static bool Set<TS, TT, TValue>(this TS source, IGetProperty<TS, TValue> sourceGetProperty, IGetOrSetProperty<TT, TValue> targetGetOrSetProperty)
{
    var sourceValue = sourceGetProperty.Invoke(source);
    var actualValue = targetGetOrSetProperty.Invoke(target);
    if(sourceValue != actualValue)
    {
        targetGetOrSetPropery.Invoke(target, sourceValue);
        return true;
    }
    return false;
}

我编造了IGetPropertyIGetOrSetProperty。是否有可能在不使用反射的情况下以某种方式实现它们(以便检查它的编译时间)?

或者有一种优雅的方式来处理这种情况吗?

编辑:该示例具有误导性,因为目标不是使用Automapper,而是以某种方式将属性表示为对象。我意识到它实际上与使用属性作为&#34; ref&#34;例如,它更像是一个与语言相关的问题,一直在这里得到解答:Passing properties by reference in C#

2 个答案:

答案 0 :(得分:3)

没有反射这是不可能的,但是表达式lambda给你编译时间检查:

public static bool Set<TTarget, TValue>(
    this TTarget target, 
    Expression<Func<TTarget, TValue>> targetProperty, 
    TValue sourceValue)
{
    var actualValue = targetProperty.Compile().Invoke(target);

    if (actualValue.Equals(sourceValue))
    {
        return false;
    }

    var property = (PropertyInfo)((MemberExpression)targetProperty.Body).Member;
    property.SetValue(target, sourceValue);
    return true;
}

用法如下:

var hasChanged = target.Set(t => t.Name, source.Name);

工作示例:https://dotnetfiddle.net/CJVxIS

为什么你不应该这样做

  • targetProperty.Compile()很慢,
  • Automapper会为您做这样的映射。

答案 1 :(得分:0)

您可以考虑序列化/反序列化。效率可能较低(但同样,反射的基本实现也很昂贵)但它在语法上更具可读性和优雅性。另一个好处是,Json.Net非常灵活,因此您可以自定义复制行为(例如将Name属性映射到另一个名称的属性)

class MyDto
{
    public string Name { get; set; }
    public string Other { get; set; }
    public string Remap { get; set; }
}

class MyBusinessObject
{
    [JsonIgnore]
    public string Other { get; set; }

    public string Name { get; set; }

    [JsonProperty(PropertyName = "Remap")]
    public string RemmapedField { get; set; }
}

public T DeepCopy<T>(object o)
{
    string json=JsonConvert.SerializeObject(o);
    T newO=JsonConvert.DeserializeObject<T>(json);
    return newO;
}

用法

MyDto source = new MyDto() { Name = "JP", Other = "Something",Remap="R" };
var target = DeepCopy<MyBusinessObject>(source);

结果:

  

姓名:&#34; JP&#34;
  其他:null
  RemmapedField:&#34; R&#34;