Bạn có thể tránh sự phản ánh trên lời gọi nếu bạn thấy vui khi so sánh dựa trên các loại thuộc tính tĩnh.
Điều này dựa vào biểu thức trong 3.5 để thực hiện phản xạ một cách đơn giản, có thể thực hiện điều này tốt hơn để giảm nỗ lực cho các loại lồng nhau nhưng điều này sẽ tốt cho hầu hết các nhu cầu.
Nếu bạn phải làm việc với các kiểu thời gian chạy thì cần phải có một số mức phản chiếu (mặc dù điều này sẽ rẻ nếu bạn nhớ lại truy cập thuộc tính và phương thức so sánh) nhưng điều này vốn phức tạp hơn nhiều. tính có thể không phù hợp như vậy, cho tổng quát đầy đủ, bạn sẽ phải xem xét quy tắc như sau:
- xem xét các loại không phù hợp để không bằng
- đơn giản để hiểu và dễ thực hiện
- không có khả năng được một hoạt động hữu ích
- Tại điểm các loại bất đồng sử dụng các tiêu chuẩn
EqualityComparer<T>.Default
thực hiện trên hai và recurse không có thêm
- lại đơn giản, hơi khó để thực hiện.
- xem xét bình đẳng nếu họ có một tập hợp con chung của các thuộc tính mà bản thân họ bằng
- phức tạp, không thực sự khủng khiếp có ý nghĩa
- xem xét bình đẳng nếu họ chia sẻ cùng một tập các thuộc tính (dựa trên tên và loại) mà chính họ là bằng nhau
- phức tạp, hãy nhập vào đánh máy vịt
Có rất nhiều tùy chọn khác nhưng điều này phải là thực phẩm để suy nghĩ là lý do tại sao phân tích toàn thời gian là khó.
(lưu ý rằng tôi đã thay đổi bạn 'lá' bảo vệ chấm dứt được những gì tôi cho là vượt trội, nếu bạn muốn chỉ cần sử dụng loại sting/giá trị đối với một số lý do cảm thấy tự do)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;
class StaticPropertyTypeRecursiveEquality<T>
{
private static readonly Func<T,T, bool> actualEquals;
static StaticPropertyTypeRecursiveEquality()
{
if (typeof(IEquatable<T>).IsAssignableFrom(typeof(T)) ||
typeof(T).IsValueType ||
typeof(T).Equals(typeof(object)))
{
actualEquals =
(t1,t2) => EqualityComparer<T>.Default.Equals(t1, t2);
}
else
{
List<Func<T,T,bool>> recursionList = new List<Func<T,T,bool>>();
var getterGeneric =
typeof(StaticPropertyTypeRecursiveEquality<T>)
.GetMethod("MakePropertyGetter",
BindingFlags.NonPublic | BindingFlags.Static);
IEnumerable<PropertyInfo> properties = typeof(T)
.GetProperties()
.Where(p => p.CanRead);
foreach (var property in properties)
{
var specific = getterGeneric
.MakeGenericMethod(property.PropertyType);
var parameter = Expression.Parameter(typeof(T), "t");
var getterExpression = Expression.Lambda(
Expression.MakeMemberAccess(parameter, property),
parameter);
recursionList.Add((Func<T,T,bool>)specific.Invoke(
null,
new object[] { getterExpression }));
}
actualEquals = (t1,t2) =>
{
foreach (var p in recursionList)
{
if (t1 == null && t2 == null)
return true;
if (t1 == null || t2 == null)
return false;
if (!p(t1,t2))
return false;
}
return true;
};
}
}
private static Func<T,T,bool> MakePropertyGetter<TProperty>(
Expression<Func<T,TProperty>> getValueExpression)
{
var getValue = getValueExpression.Compile();
return (t1,t2) =>
{
return StaticPropertyTypeRecursiveEquality<TProperty>
.Equals(getValue(t1), getValue(t2));
};
}
public static bool Equals(T t1, T t2)
{
return actualEquals(t1,t2);
}
}
để thử nghiệm Tôi đã sử dụng các thông tin sau:
public class Foo
{
public int A { get; set; }
public int B { get; set; }
}
public class Loop
{
public int A { get; set; }
public Loop B { get; set; }
}
public class Test
{
static void Main(string[] args)
{
Console.WriteLine(StaticPropertyTypeRecursiveEquality<String>.Equals(
"foo", "bar"));
Console.WriteLine(StaticPropertyTypeRecursiveEquality<Foo>.Equals(
new Foo() { A = 1, B = 2 },
new Foo() { A = 1, B = 2 }));
Console.WriteLine(StaticPropertyTypeRecursiveEquality<Loop>.Equals(
new Loop() { A = 1, B = new Loop() { A = 3 } },
new Loop() { A = 1, B = new Loop() { A = 3 } }));
Console.ReadLine();
}
}
Không được (t1 là ValueType | t1 là chuỗi)? Với || nếu điều kiện đầu tiên bị lỗi thì điều kiện thứ hai không được kiểm tra. System.String là một kiểu tham chiếu, không phải là một kiểu giá trị. –