मुझे एक इकाई ढांचे परियोजना में एक नेविगेशन संपत्ति के साथ कोई समस्या है। ,क्यों आईसीओलेक्शन <>। मेरे ओवरराइड बराबर और IEquatable <> इंटरफ़ेस को अनदेखा करता है?
[DataContract]
[Table("MobileDeviceInfo")]
public class MobileDeviceInfo : IEquatable<MobileDeviceInfo>
{
[DataContract]
public enum MobilePlatform
{
[EnumMember]
// ReSharper disable once InconsistentNaming because correct spelling is iOS
iOS = 1,
[EnumMember] Android = 2,
[EnumMember] WindowsPhone = 3,
[EnumMember] Blackberry = 4
}
// constructors omitted ...
[DataMember, Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int DeviceInfoId { get; private set; }
[DataMember, Required, Index(IsUnique = true), MinLength(DeviceTokenMinLength), MaxLength(DeviceTokenMaxLength)]
public string DeviceToken { get; set; }
[DataMember, Required, MinLength(DeviceNameMinLength), MaxLength(DeviceNameMaxLength)]
public string DeviceName { get; set; }
[DataMember, Required]
public MobilePlatform Platform { get; set; }
// other properties ...
[DataMember]
public virtual MobileUser MobileUser { get; private set; }
/// <summary>
/// The foreign-key to the MobileUser.
/// This is not the VwdId which is stored in MobileUser
/// </summary>
[DataMember, ForeignKey("MobileUser")]
public int UserId { get; set; }
public bool Equals(MobileDeviceInfo other)
{
if (other == null) return false;
return DeviceToken == other.DeviceToken;
}
public override string ToString()
{
return "Bah"; // implementation omitted
public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj)) return true;
MobileDeviceInfo other = obj as MobileDeviceInfo;
if (other == null) return false;
return Equals(other);
}
public override int GetHashCode()
{
// ReSharper disable once NonReadonlyMemberInGetHashCode
return DeviceToken.GetHashCode();
}
#region constants
// irrelevant
#endregion
}
आप देख सकते हैं:
public virtual ICollection<MobileDeviceInfo> DeviceInfos { get; private set; }
इस वर्ग MobileDeviceInfo
है:
[DataContract]
[Table("MobileUser")]
public class MobileUser: IEquatable<MobileUser>
{
// constructors omitted....
/// <summary>
/// The primary-key of MobileUser.
/// This is not the VwdId which is stored in a separate column
/// </summary>
[DataMember, Key, Required, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[DataMember, Required, Index(IsUnique = true), MinLength(VwdIdMinLength), MaxLength(VwdIdMaxLength)]
public string VwdId { get; set; }
// other properties omitted ...
[DataMember]
public virtual ICollection<MobileDeviceInfo> DeviceInfos { get; private set; }
public bool Equals(MobileUser other)
{
return this.UserId == other?.UserId || this.VwdId == other?.VwdId;
}
public override bool Equals(object obj)
{
if(object.ReferenceEquals(this, obj))return true;
MobileUser other = obj as MobileUser;
if (other == null) return false;
return this.Equals(other);
}
public override int GetHashCode()
{
// ReSharper disable once NonReadonlyMemberInGetHashCode
return VwdId.GetHashCode();
}
public override string ToString()
{
return "foo"; // omitted actual implementation
}
#region constants
// irrelevant
#endregion
}
प्रासंगिक हिस्सा इस नेविगेशन संपत्ति है:
यहाँ वर्ग MobileUser
है यह IEquatable<MobileDeviceInfo>
लागू करता है औरओवरराइड करता है System.Object
सेऔर GetHashCode
।
मेरे पास निम्न परीक्षण है, मुझे उम्मीद है कि Contains
मेरे Equals
पर कॉल करेगा लेकिन ऐसा नहीं है। यह बजाय Object.ReferenceEquals
उपयोग करने के लिए लगता है, इसलिए मेरे डिवाइस नहीं मिलेगा, क्योंकि यह एक अलग संदर्भ है:
var userRepo = new MobileUserRepository((ILog)null);
var deviceRepo = new MobileDeviceRepository((ILog)null);
IReadOnlyList<MobileUser> allUser = userRepo.GetAllMobileUsersWithDevices();
MobileUser user = allUser.First();
IReadOnlyList<MobileDeviceInfo> allDevices = deviceRepo.GetMobileDeviceInfos(user.VwdId, true);
MobileDeviceInfo device = allDevices.First();
bool contains = user.DeviceInfos.Contains(device);
bool anyEqual = user.DeviceInfos.Any(x => x.DeviceToken == device.DeviceToken);
Assert.IsTrue(contains); // no, it's false
LINQ
के Enumerable.Any
उम्मीद true
रिटर्न के साथ दूसरा दृष्टिकोण।
यदि मैं user.DeviceInfos.Contains(device)
का उपयोग नहीं करता लेकिन user.DeviceInfos.ToList().Contains(device)
यह List<>.Contains
से Equals
का उपयोग करने के बाद से अपेक्षा करता है।
ICollection<>
के वास्तविक प्रकार एक System.Collections.Generic.HashSet<MobileDeviceInfo>
प्रतीत हो रहा है, लेकिन अगर मैं कोड भी एक HashSet<>
इसे फिर से अपेक्षा के अनुरूप काम करता है का उपयोग करता है निम्नलिखित का उपयोग करें:
bool contains = new HashSet<MobileDeviceInfo>(user.DeviceInfos).Contains(device); // true
तो क्यों केवल संदर्भ तुलना की जाती है और अपने कस्टम Equals
है अवहेलना करना?
अद्यतन:
और भी अधिक भ्रमित परिणाम है false
है, भले ही मैं इसे HashSet<MobileDeviceInfo>
लिए डाली:
// still false
bool contains2 = ((HashSet<MobileDeviceInfo>)user.DeviceInfos).Contains(device);
// but this is true as already mentioned
bool contains3 = new HashSet<MobileDeviceInfo>(user.DeviceInfos).Contains(device);
अद्यतन 2:: इस का कारण यह वास्तव में लगता है हो सकता है कि हैशसेट्स अलग तुलनाकर्ताओं का उपयोग करें।
System.Data.Entity.Infrastructure.ObjectReferenceEqualityComparer
और मानक HashSet<>
एक का उपयोग करता है: इकाई-ढांचा-HashSet एक का उपयोग करता है
GenericEqualityComparer<T>
यही मुद्दा बताते हैं, हालांकि मुझे समझ नहीं आता क्यों इकाई की रूपरेखा एक कार्यान्वयन कि कस्टम पर ध्यान नहीं देता का उपयोग करता है कुछ परिस्थितियों में Equals
कार्यान्वयन। यह एक बुरा जाल है, है ना?
निष्कर्ष: Contains
का उपयोग करता है, तो आप क्या comparer उपयोग किया जाएगा पता है या अधिभार कि एक कस्टम comparer लेता है साथ Enumerable.Contains
का उपयोग नहीं करते कभी नहीं:, एफई स्रोत से
bool contains = user.DeviceInfos.Contains(device, EqualityComparer<MobileDeviceInfo>.Default); // true
'आईसीओलेक्शन 'स्वयं कुछ भी नहीं करेगा - यह सिर्फ एक इंटरफ़ेस है। क्या कार्यान्वयन का उपयोग किया जा रहा है? क्या आप ईएफ का उपयोग किये बिना इसे पुन: पेश कर सकते हैं? –
@ जोनस्केट: यह आलसी लोडिंग का उपयोग नहीं कर रहा है, इसका प्रकार वास्तव में एक हैशसेट <मोबाइलडिवाइस इंफो>> है। यही इतना भ्रमित है। अंतिम पैराग्राफ को देखो। कोई एसक्यूएल उत्पन्न नहीं होता है। –
आपके हैश कोड को एक म्यूटेबल प्रॉपर्टी पर आधारित है, तो क्या होता है यदि ईएफ आइटम हैशसेट में जोड़ता है और * फिर * संपत्ति मान सेट करता है? –