1.引言
上一篇文章介绍了对象驻留,请查考值对象共享 。 string驻留,还是对象共享都必须要进行对象判等,以一定的规则进行比较,相同的就归为同一个引用名下。对象判等就应该要查考Object的判断方法了。
2.判等
认识一下System.Object类中实现的几个对象判等方法,它们是:
- public virtual bool Equals(object obj) 虚方法,比较对象实例是否相等
- public static bool Equals(object objA, object objB) 静态方法,比较对象实例是否相等
- public static bool ReferenceEquals(object objA, object objB) 静态方法,比较两个引用是否指向同一对象
下面看看这几个方法具体实现的
public static bool Equals(object objA, object objB) { //是否同一个实例 if (objA == objB) { return true; } if ((objA != null) && (objB != null)) { //实例虚方法Equals return objA.Equals(objB); } return false; } public static bool ReferenceEquals(object objA, object objB) { //是否同一个实例 return (objA == objB); } public virtual bool Equals(object obj) { return InternalEquals(this, obj); } //InternalEquals 方法表示为 bool InternalEquals(object objA, object objB) { if (objA == objB) { return true; } else { return false; } }
可以看出
- Equals(object objA, object objB) 静态方法,先是判断是否同一个实例,这点同ReferenceEquals(object objA, object objB) 静态方法一样,再调用Equals(object obj) 虚方法。
- ReferenceEquals(object objA, object objB) 静态方法比较的是实例是否相同。
- Equals(object obj) 虚方法 比较的也是实例是否相同。
- 3个方法,默认都是比较实例是否相同,如果new 两个对象,必定判等返回false,只有通过重写Equals(object obj) 虚方法
3.驻留方式
string已经重写了object的Equals方法,先看下面例子
string s1 = "Hello"; string s2 = "Hello"; Console.WriteLine(string.ReferenceEquals(s1, s2)); // True :驻留 同一个对象 Console.WriteLine(s1 == s2); //True :已重写Equal, 更何况是同一个对象 string s3 = "He"; s3 += "llo"; Console.WriteLine(string.ReferenceEquals(s1, s3)); // False :不是同一个对象 Console.WriteLine(s1 == s3); //True :已重写Equal,比较的是值 string s4 = String.Intern(s3); Console.WriteLine(string.ReferenceEquals(s1, s4)); // True :通过 Intern方法进行驻留,返回同一个对象 Console.WriteLine(s1 == s4); //True :已重写Equal
上面两种方式驻留,一是 声明创建的时候,二是通过String.Intern方法。
在上一节中就是通过声明创建时驻留,请查考值对象共享,下面看网上的另一个例子。
public class ValueFactory<TEntity> where TEntity : class { private HashSet<WeakReference> weakReferences; private weakReferenceComparer comparer; public ValueFactory() { comparer = new weakReferenceComparer(); weakReferences = comparer.WeakReferences; } public TEntity Intern(TEntity value) { if (value != null) { WeakReference weakReference = new WeakReference(value); Monitor.Enter(weakReferences); try { if (weakReferences.Contains(weakReference)) value = comparer.EqualValue; else weakReferences.Add(weakReference); foreach (WeakReference remove in comparer.Remove) weakReferences.Remove(remove); comparer.Remove.Clear(); } finally { Monitor.Exit(weakReferences); } } return value; } //比较弱引用 private class weakReferenceComparer : IEqualityComparer<WeakReference> { public HashSet<WeakReference> WeakReferences; public List<WeakReference> Remove = new List<WeakReference>(); public TEntity EqualValue; public weakReferenceComparer() { WeakReferences = new HashSet<WeakReference>(this); } public bool Equals(WeakReference left, WeakReference right) { if (left.IsAlive) return (EqualValue = (TEntity)left.Target).Equals((TEntity)right.Target); else Remove.Add(left); return false; } public int GetHashCode(WeakReference value) { return ((TEntity)value.Target).GetHashCode(); } } }
下面声明User,User类重写了Object的判等虚方法
public class User { public string Name { get; set; } public string Password { get; set; } //测试用 public Guid instanceId = Guid.NewGuid(); public User() { Console.WriteLine("创建实例ID:{0}", instanceId); } ~User() { Console.WriteLine("释放ID:{0}", instanceId); } //重写比较值相等 public override bool Equals(object obj) { if (!(obj is User)) return false; return (obj as User).Name == Name && (obj as User).Password == Password; } public override int GetHashCode() { return (this.Name != null ? this.Name.GetHashCode() : 0) ^ (this.Password != null ? this.Password.GetHashCode() : 0); } }
调用如下:
class Program { static void Main(string[] args) { fu(); User u5 = factory.Intern(new User { Name = "qlin", Password = "1234" }); Console.WriteLine("U5 ID:{0} {1}", u5.instanceId, "\n\r--------------"); GC.Collect(); Console.Read(); } static ValueFactory<User> factory = new ValueFactory<User>(); static void fu() { User u1 = factory.Intern(new User { Name = "qlin", Password = "1234" }); //值相同,u2直接引用指向u1,引用也相同 User u2 = factory.Intern(new User { Name = "qlin", Password = "1234" }); User u3 = factory.Intern(new User { Name = "Qlin", Password = "1234" }); User u4 = factory.Intern(new User { Name = "lin", Password = "123456" }); Console.WriteLine(u1.Equals(u2)); Console.WriteLine(object.ReferenceEquals(u1, u2) + "| U1 ID:" + u1.instanceId + "\n\r--------------"); Console.WriteLine(u1.Equals(u3)); Console.WriteLine(object.ReferenceEquals(u1, u3) + "\n\r--------------"); Console.WriteLine(u3.Equals(u4)); Console.WriteLine(object.ReferenceEquals(u3, u4) + "\n\r--------------"); } }
4.小结
上面示例是通过弱引用的方式,好处就是即使弱引用对象weakReference还在,但是弱引用weakReference包装的对象User是可以释放的,如果User为null,即没有引用,即GC可以回收了,那weakReference就访问不到User了,这时也可以删除这个weakReference了。 也可以考虑缓存Cache等其他方式。
作者:Qlin
出处:http://www.cnblogs.com/qqlin/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。