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等其他方式。

 

 

posted on 2012-12-28 11:39  Qlin  阅读(936)  评论(0编辑  收藏  举报