无需装箱即可对类属性进行赋值和比较

问题描述 投票:0回答:1

考虑以下场景:

public interface ICloneable<T>:
    ICopyable<T> where T : ICloneable<T>, new()
{
    public T CloneTyped ();
}

public interface ICopyable<T>
    where T : ICopyable<T>
{
    public T CopyTo (T other);
    public T CopyFrom (T other);
}

public interface IDirtyable<T>
    where T : IDirtyable<T>
{
    // Compares the current object [this] to an unaltered object [referenceObject].
    public bool IsDirty (T referenceObject);
}

public partial class Model:
    ICloneable<Model>,
    ICopyable<Model>,
    IDirtyable<Model>
{
    public virtual long Id { get; set; }
    public virtual DateTime DateTimeCreated { get; set; }
    public virtual DateTime DateTimeModified { get; set; }
    public virtual string Name { get; set; } = string.Empty;

    public Model CloneTyped () => new Model().CopyFrom(this);
    public Model CopyFrom (Model other) => other.CopyTo(this);

    public Model CopyTo (Model other)
    {
        other.Id = this.Id;
        other.DateTimeCreated = this.DateTimeCreated;
        other.DateTimeModified = this.DateTimeModified;
        other.Name = this.Name;

        return (other);
    }

    public bool IsDirty (Model referenceObject)
    {
        return
            this.Id == referenceObject.Id
            && this.DateTimeCreated == referenceObject.DateTimeCreated
            && this.DateTimeModified == referenceObject.DateTimeModified
            && this.Name == referenceObject.Name;
    }
}

请注意,就这个问题而言,我对

INotifyPropertyChanged
或其他类似机制不感兴趣。此外,假设类
Model
有数十个标量属性(我们不关心复合类型)。

因此我们留下了一个接口模式,对两个相同类型的对象执行比较或赋值操作。现在,因为我知道这些接口实现应该处理的属性列表,所以我可以执行如下操作:

    public bool IsDirtyUsingReflection (Model referenceObject)
    {
        var equal = true;
        var propertyNames = new [] { nameof(this.Id), nameof(this.DateTimeCreated), nameof(this.DateTimeModified), nameof(this.Name), };
        var properties = this.GetType().GetProperties().Where(p => propertyNames.Contains(p.Name));

        foreach (var property in properties)
        {
            equal
                &= property.GetValue(this)
                ?.Equals(property.GetValue(referenceObject))
                ?? false;

            if (!equal) { return (true); }
        }

        return (false);
    }

所以,问题是,我如何维护属性列表并在没有反射或装箱的情况下比较/分配它们?

我考虑过维护

Expression
类型等属性。

var properties = new Expression<Func<T, object?>> [] {...};

任何指导将不胜感激以实现以下目标:

  • 维护
    static
    属性列表。
  • 无需装箱即可执行赋值和比较操作。
  • 无需反射即可执行赋值和比较操作。
  • 维护避免装箱的
    Expression
    对象或编译的 lambda 列表。在类型级别 (
    static1
    ) 进行编译和/或装箱就可以了。

要考虑的数据类型仅包括内置值类型、字符串、枚举和实现

IEquitable
的结构。

c# .net lambda reflection expression
1个回答
0
投票

表达式生成或原始引用发射(

ILGenerator
)确实是可行的,但是:我想知道是否更好的方法是编写一个 Roslyn 代码生成器来为您执行此操作。例如,您可以写:

public partial class Model
{
    public partial bool IsDirty (Model referenceObject);
}

生成器可以检测并根据构建期间发现的成员输出缺失的一半:

partial class Model
{
    public partial bool IsDirty (Model referenceObject)
    {
        return
            this.Id == referenceObject.Id
            && this.DateTimeCreated == referenceObject.DateTimeCreated
            && this.DateTimeModified == referenceObject.DateTimeModified
            && this.Name == referenceObject.Name;
    }
}

也许需要更多工作,但从长远来看,它可以被冻结得更加灵活和高性能 - 维护表达式/引用发出代码非常困难(问我怎么知道......),在哪里进行调整到发电机输出:简单。

© www.soinside.com 2019 - 2024. All rights reserved.