Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 比较.NET中的GUID时出现意外行为_C#_Lambda_Comparison_Extension Methods_Guid - Fatal编程技术网

C# 比较.NET中的GUID时出现意外行为

C# 比较.NET中的GUID时出现意外行为,c#,lambda,comparison,extension-methods,guid,C#,Lambda,Comparison,Extension Methods,Guid,我试图创建一个如下所示的扩展方法 public static IEnumerable<T> Distinct<T>(this IEnumerable<T> value, IEnumerable<T> compareTo, Func<T, object> compareFieldPredicate) { return value.Where(o => !compareTo.Exists(p => compareFiel

我试图创建一个如下所示的扩展方法

public static IEnumerable<T> Distinct<T>(this IEnumerable<T> value, IEnumerable<T> compareTo, Func<T, object> compareFieldPredicate)
{
    return value.Where(o => !compareTo.Exists(p => compareFieldPredicate.Invoke(p) == compareFieldPredicate.Invoke(o)));
}
IEnumerable<MyCollection> distinctValues = MyCollection.Distinct(MyOtherCollection, o => o.ID); //Note that o.ID is a guid
公共静态IEnumerable Distinct(此IEnumerable值、IEnumerable compareTo、Func compareFieldPredicate)
{
返回值。其中(o=>!compareTo.Exists(p=>compareFieldPredicate.Invoke(p)==compareFieldPredicate.Invoke(o));
}
我的想法是我可以做这样的事情

public static IEnumerable<T> Distinct<T>(this IEnumerable<T> value, IEnumerable<T> compareTo, Func<T, object> compareFieldPredicate)
{
    return value.Where(o => !compareTo.Exists(p => compareFieldPredicate.Invoke(p) == compareFieldPredicate.Invoke(o)));
}
IEnumerable<MyCollection> distinctValues = MyCollection.Distinct(MyOtherCollection, o => o.ID); //Note that o.ID is a guid
IEnumerable distinctValues=MyCollection.Distinct(MyOtherCollection,o=>o.ID)//请注意,o.ID是一个guid
现在,在这一点上,我本以为只有我独特的项目返回给我,但我发现,这是从来没有这样的情况

在进一步研究后,使用以下代码分解此方法

Guid guid1 = Guid.NewGuid();
Guid guid2 = new Guid(guid1.ToString());

Func<MyObject, object> myFunction = o => o.ID;
Func<MyObject, object> myFunction1 = o => o.ID;

bool result = myFunction(MyObject) == myFunction1(MyObject);
//result = false
guid1=Guid.NewGuid();
Guid guid2=新Guid(guid1.ToString());
Func myFunction=o=>o.ID;
Func myFunction1=o=>o.ID;
bool result=myFunction(MyObject)==myFunction1(MyObject);
//结果=错误
我发现事实上,即使guid是相同的,比较也总是返回false

这是什么原因

bool result = (guid1==guid2); //result -> true
您可以尝试在myfunction和myfunction1中将返回类型对象更改为GUID

Func<MyObject, Guid> myFunction = o => o.ID;
Func<MyObject, Guid> myFunction1 = o => o.ID;
Func myFunction=o=>o.ID;
Func myFunction1=o=>o.ID;
否则,返回值(true)将被装箱到对象,并检查引用相等,这是false。

更改为使用

Func<MyObject, Guid> myFunction = o => o.ID;
Func<MyObject, Guid> myFunction1 = o => o.ID;
Func myFunction=o=>o.ID;
Func myFunction1=o=>o.ID;
这是因为你的函数被定义为

Func<MyObject, object>
Func
myFunction
myFunction1
返回的Guid将被装箱到两个不同的OBEJCT中。有关.NET中的装箱和取消装箱功能,请参见

因此,在进行比较时,会比较两个不同的对象


对象中
Equals
的默认实现是执行引用相等检查。它没有检查装箱的值。有关如何实现object.Equals的更多详细信息,请参阅。

如果将lambda更改为返回Guid,则它可以工作:

Func<MyObject, Guid> myFunction = o => o.ID;
Func<MyObject, Guid> myFunction1 = o => o.ID;
Func myFunction=o=>o.ID;
Func myFunction1=o=>o.ID;

您的问题是,在比较GUI之前,您正在将其装箱到对象中。考虑这个代码:

Guid g1 = Guid.NewGuid();
var g2 = g1;

Console.WriteLine(g1 == g2);

object o1 = g1;
object o2 = g2;

Console.WriteLine(o1 == o2);
这实际上产生了:

true
false
因为“o1”和“o2”虽然等于相同的Guid,但不是相同的对象

如果确实希望“独特”扩展方法不绑定到特定类型(如Guid),可以执行以下操作:

public static IEnumerable<TItem> Distinct<TItem, TProp>(this IEnumerable<TItem> value, IEnumerable<TItem> compareTo, Func<TItem, TProp> compareFieldPredicate)
    where TProp : IEquatable<TProp>
{
    return value.Where(o => !compareTo.Any(p => compareFieldPredicate(p).Equals(compareFieldPredicate(o))));
} 
公共静态IEnumerable Distinct(此IEnumerable值、IEnumerable compareTo、Func compareFieldPredicate)
其中TProp:IEquatable
{
返回值。其中(o=>!compareTo.Any(p=>compareFieldPredicate(p).Equals(compareFieldPredicate(o)));
} 

正如其他人所说,您的
compareFieldPredicate
返回一个
对象
,其运算符
=
使用
对象。ReferenceEquals
,而不是
对象。Equals
,因此您的代码总是检查对象标识,而不是相等

解决这个问题的一个方法是使用
object.Equals
方法,而不是运算符
=

public static IEnumerable<T> Distinct<T>(
    this IEnumerable<T> value, 
    IEnumerable<T> compareTo, 
    Func<T, object> compareFieldPredicate
)
{
    return value.Where(o => !compareTo.Exists(
        p => object.Equals(compareFieldPredicate(p), compareFieldPredicate(o))
    ));
}
但是,
Distinct
方法的大部分功能已经由
LINQ方法

您可以通过提供
IEqualityComparer
的实现来重写实现:

private class KeyEqualityComparer<T, TKey> : IEqualityComparer<T>
{
    private readonly Func<T, TKey> _keySelector;

    public KeyEqualityComparer(Func<T, TKey> keySelector)
    { _keySelector = keySelector; }

    public int GetHashCode(T item)
    { return _keySelector(item).GetHashCode(); }

    public bool Equals(T x, T y)
    { return EqualityComparer<TKey>.Default.Equals(_keySelector(x), _keySelector(y)); }
}

public static IEnumerable<T> ExceptBy<T, TKey>(
    this IEnumerable<T> first, 
    IEnumerable<T> second, 
    Func<T, TKey> keySelector
)
{
    return first.Except(second, new KeyEqualityComparer<T, TKey>(keySelector));
}
私有类KeyEqualityComparer:IEqualityComparer
{
专用只读功能键选择器;
公钥平等比较程序(Func密钥选择器)
{u keySelector=keySelector;}
公共int GetHashCode(T项)
{return_keySelector(item).GetHashCode();}
公共布尔等于(TX,TY)
{return EqualityComparer.Default.Equals(_keySelector(x),_keySelector(y));}
}
公共静态IEnumerable ExceptBy(
这是第一次,
我数不清的秒,
Func键选择器
)
{
首先返回。除了(第二个,新的KeyEqualityComparer(keySelector));
}

包含guid类型字段ID的自定义类。抱歉,如果这不清楚…可能我遗漏了什么,但是如果它是一个类型,为什么要将它传递到
myFunction
myFunction1
?这就是我将如何表达我的答案的方式,但是由于两个返回的对象是相同的引用,我不清楚为什么它返回false。但是,将它们更改为Guid会修复它。@Michael由
myFunction
myFunction1
返回的Guid将被装箱到两个不同的对象中。请参阅此链接,非常感谢您提供了简明的答案。我想这可能是类似的,但我没有100%的理解。顺便说一句,Equatable泛型约束是一个非常好的方法。