开发者

Maintain one to one mapping between objects

开发者 https://www.devze.com 2022-12-27 17:30 出处:网络
i have the following two classes that provide a one to one mapping between each other.How do i handle null values, when i run the second test i get a stackoverflow exception. How can i stop this recur

i have the following two classes that provide a one to one mapping between each other. How do i handle null values, when i run the second test i get a stackoverflow exception. How can i stop this recursive cycle? Thanks

[TestMethod]
public void SetY()
{
    var x = new X();
    var y = new Y();

    x.Y = y;

    Assert.AreSame(x.Y, y);
    Assert.AreSame(y.X, x);
}

[TestMethod]
public void SetYToNull()
{
    var x = new X();
    var y = new Y();

    x.Y = y;
    y.X = null;

    Assert.IsNu开发者_运维问答ll(x.Y);
    Assert.IsNull(y.X);
}

public class X
{
    private Y _y;

    public Y Y
    {
        get { return _y; }
        set
        {
            if(_y != value)
            {
                if(_y != null)
                {
                    _y.X = null;
                }

                _y = value;

                if(_y != null)
                {
                    _y.X = this;
                }
            }
        }
    }
}

public class Y
{
    private X _x;

    public X X
    {
        get { return _x; }
        set
        {
            if (_x != value)
            {
                if (_x != null)
                {
                    _x.Y = null;
                }

                _x = value;

                if (_x != null)
                {
                    _x.Y = this;
                }
            }
        }
    }
}


That works fine:

public class ClassX
{
    private ClassY _Y;

    public ClassY Y
    {
        get { return _Y; }
        set
        {
            if (_Y != value)
            {
                var oldY = _Y;
                _Y = value;

                if (_Y == null)
                {
                    oldY.X = null;
                }
                else
                {
                    _Y.X = this;    
                }
            }
        }
    }
}

public class ClassY
{
    private ClassX _X;

    public ClassX X
    {
        get { return _X; }
        set
        {
            if (_X != value)
            {
                var oldX = _X;

                _X = value;
                if (_X == null)
                {
                    oldX.Y = null;
                }
                else
                {
                    _X.Y = this;    
                }

            }
        }
    }
}


When setting y.X = null;, what happens is that it will try to set y.X to null as _x is not null, which in turn tries to set (y.X).Y to null since _y in x is still not null yet and ... well you get the idea - an endless loop.

I've changed it so that the member value is assigned first before assigning to the property of the member variable.

public class X
{
    private Y _y;

    public Y Y
    {
        get { return _y; }
        set
        {
            if (_y != value)
            {
                Y temp = _y;

                _y = value;

                // If new value is not null
                if (_y != null)
                {
                    _y.X = this;
                }
                // If old value is not null but new value is 
                else if (temp != null)
                {
                    temp.X = null;
                }
            }
        }
    }
}

public class Y
{
    private X _x;

    public X X
    {
        get { return _x; }
        set
        {
            if (_x != value)
            {
                X temp = _x;

                _x = value;

                // If new value is not null
                if (_x != null)
                {
                    _x.Y = this;
                }
                // If old value is not null but new value is 
                else if (temp != null)
                {
                    temp.Y = null;
                }
            }
        }
    }
}


You're running into infinite loop here.

If you just don't want to get nulls, use this:

get 
{ 
    if (_y == null)
        _y = new Y();
    return _y; 
}


Use separate entity to store relationships between objects. Like this:

[TestFixture]
    public class Tester
    {
        [Test]
        public void SetY()
        {
            var refs = new References();

            var x = new X(refs);
            var y = new Y(refs);

            x.Y = y;

            Assert.AreSame(x.Y, y);
            Assert.AreSame(y.X, x);
        }

        [Test]
        public void SetYToNull()
        {
            var refs = new References();

            var x = new X(refs);
            var y = new Y(refs);


            x.Y = y;
            y.X = null;

            Assert.IsNull(x.Y);
            Assert.IsNull(y.X);
        }
    }

    public class References
    {
        private IDictionary<X, Y> refs = new Dictionary<X, Y>();

        public bool Contains(X x, Y y)
        {
            if (!refs.ContainsKey(x)) return false;
            if (refs[x] != y) return false;

            return true;
        }

        public void Delete(X x)
        {
            refs.Remove(x);
        }

        public void Add(X x, Y y)
        {
            refs.Add(x, y);
        }

        public Y Get(X x)
        {
            return refs.ContainsKey(x) ? refs[x] : null;
        }

        public X Get(Y y)
        {
            var pairs = refs.Where(r => r.Value == y);

            return pairs.Any() ? pairs.FirstOrDefault().Key : null;
        }

        public void Delete(Y y)
        {
            X x = Get(y);

            if (x != null)
            {
                Delete(x);
            }
        }
    }

    public class X
    {
        private readonly References refs;

        public X(References refs)
        {
            this.refs = refs;
        }

        public Y Y
        {
            get { return refs.Get(this); }
            set
            {
                if (value == null)
                {
                    refs.Delete(this);
                }
                else
                {
                    if (!refs.Contains(this, value))
                    {
                        refs.Add(this, value);
                    }
                }
            }
        }
    }

    public class Y
    {
        private References refs;

        public Y(References refs)
        {
            this.refs = refs;
        }

        public X X
        {
            get { return refs.Get(this); }
            set
            {
                if (value == null)
                {
                    refs.Delete(this);
                }
                else
                {
                    if (!refs.Contains(value, this))
                    {
                        refs.Add(value, this);
                    }
                }
            }
        }
    }
0

精彩评论

暂无评论...
验证码 换一张
取 消