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

能否用AutoMapper实现对象相等性测试?新增字段自动纳入校验

Can AutoMapper Handle This Equality Check? (And Better Alternatives)

First off: AutoMapper is not the right tool for this job. AutoMapper’s core purpose is to map properties between different object types, not to implement value-based equality checks for a single class. You could technically hack together something using its mapping configuration to compare properties, but that would be a huge misuse of the library—you’d be fighting against its intended design, and the solution would be fragile, hard to maintain, and perform poorly compared to purpose-built approaches.

Now let’s dive into the best ways to solve your actual requirement: implementing equality checks that automatically include new string fields (and scale to non-string fields later).

Option 1: Reflection-Based Equality (Quick, Flexible, But Less Performant)

If you need a simple, no-compiler-setup solution, you can use reflection to dynamically iterate over all string fields in your Book class and compare them. Here’s a rough implementation:

public class Book
{
    public string Title;
    public string Author;
    // New fields like Publisher will be automatically included

    public override bool Equals(object obj)
    {
        if (obj is not Book other)
            return false;
        
        // Get all public instance string fields (adjust BindingFlags for non-public if needed)
        var stringFields = GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)
            .Where(f => f.FieldType == typeof(string));

        foreach (var field in stringFields)
        {
            var value1 = field.GetValue(this);
            var value2 = field.GetValue(other);
            if (!string.Equals(value1, value2, StringComparison.Ordinal))
                return false;
        }

        return true;
    }

    public override int GetHashCode()
    {
        var hash = new HashCode();
        var stringFields = GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)
            .Where(f => f.FieldType == typeof(string));
        
        foreach (var field in stringFields)
        {
            hash.Add(field.GetValue(this) as string);
        }
        return hash.ToHashCode();
    }
}

Pros & Cons:

  • ✅ Automatically includes new string fields without code changes
  • ✅ Easy to implement right now
  • ❌ Reflection has performance overhead (not ideal for high-throughput scenarios)
  • ❌ You’ll need to adjust the logic if you add non-string fields (e.g., handle value types, reference types with their own equality checks)

Option 2: Source Generators (Best for Performance & Maintainability)

For a production-grade solution, use .NET Source Generators (available in .NET 6+). This lets you generate compile-time equality code that’s as fast as hand-written, and it automatically updates when you add new fields.

Here’s how to approach it:

  1. Create a custom attribute (e.g., AutoEqualityCheckAttribute) to mark classes that need automatic equality logic.
  2. Write a source generator that scans for classes with this attribute, collects all string fields (or all fields/properties if you want to support non-string later), and generates Equals and GetHashCode methods.

Example generated code for your Book class would look like hand-written equality checks:

public override bool Equals(object obj)
{
    return obj is Book other && 
           string.Equals(Title, other.Title, StringComparison.Ordinal) &&
           string.Equals(Author, other.Author, StringComparison.Ordinal) &&
           string.Equals(Publisher, other.Publisher, StringComparison.Ordinal); // Auto-added when you add the field
}

public override int GetHashCode()
{
    return HashCode.Combine(Title, Author, Publisher);
}

Pros & Cons:

  • ✅ Zero runtime overhead (code is generated at compile time)
  • ✅ Automatically includes new fields/properties without manual changes
  • ✅ Easy to extend to non-string fields (just adjust the generator to handle value types, IEquatable<T> types, etc.)
  • ❌ Requires setting up a source generator project (a bit more initial work, but worth it for long-term maintainability)

Option 3: Use C# Records (Simplest for Value Equality)

If you’re able to refactor your Book class into a record type, C# automatically implements value-based equality that includes all properties (you can adjust to use fields too). When you add new properties/fields, the equality check updates automatically.

public record Book(string Title, string Author);
// Later add Publisher: public record Book(string Title, string Author, string Publisher);

Pros & Cons:

  • ✅ No manual equality code needed—C# handles it all
  • ✅ Automatically includes new properties/fields
  • ❌ Records are immutable by default (you can use init properties for mutable records, but it’s a different pattern than a regular class)
  • ❌ Less control over equality logic (e.g., custom string comparison) unless you override the generated methods

Handling Non-String Fields

When you need to support non-string fields later:

  • For reflection: Extend the logic to check field types—use object.Equals for value types, check if the type implements IEquatable<T> and call that method, or add custom handling for specific types (e.g., DateTime with a specific kind).
  • For source generators: Update the generator to generate appropriate comparison logic based on field type (e.g., int uses ==, DateTime uses DateTime.Equals, reference types use their Equals method).
  • For records: C# automatically handles value types and reference types using their default equality checks, but you can override Equals and GetHashCode if you need custom logic.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:34:03