2010-04-23 5 views
3

나는 서로간에 일대일 매핑을 제공하는 다음 두 클래스가 있습니다. 어떻게 두 번째 테스트를 실행할 때 null 값을 처리 할 stackoverflow 예외가 얻을. 이 재귀 사이클을 어떻게 멈출 수 있습니까? 감사합니다.개체 간 일대일 매핑 유지

[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.IsNull(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; 
       } 
      } 
     } 
    } 
} 
+1

수행하려는 작업은 무엇입니까? –

+0

내가 x.Y를 null로 설정하면 둘 다 서로를 참조하기 때문에 x.Y와 y.X가 모두 null 일 것으로 예상됩니다. 기본적으로 두 객체간에 양방향 참조를 유지하려고합니다. –

+0

이 디자인을 다시 고려할 수 있습니다. –

답변

1

잘 작동하는지 :

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;  
       } 

      } 
     } 
    } 
} 
0

여기 무한 루프로 연결됩니다. 그냥 null의를 얻을하지 않으려면

, 이것을 사용 :

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

를 사용하여 별도의 엔티티 객체 사이의 관계를 저장합니다. 이처럼 :

[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); 
        } 
       } 
      } 
     } 
    } 
1

y.X = null; 설정, 무슨 일하는 그것뿐만 _x null로 YX을 설정하려고하는 것입니다 (다시 설정하려고하는, null가 아닌 yX) .Y는 x의 _y가 여전히 null이 아니기 때문에 null로, 아이디어를 얻습니다. 끝없는 반복입니다.

멤버 변수의 속성에 할당하기 전에 멤버 값이 먼저 할당되도록 변경했습니다.

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; 
       } 
      } 
     } 
    } 
} 
+0

당신은 이것을 제거 할 수 있습니다 :'if (temp! = null)'setter의 시작 부분에서'_x! = value'를 검사하고 새로운 값이'null'이면 temp 변수는 항상 null이 아니기 때문에. 내 대답을 보라. – bniwredyc

+0

네가 맞아! 감사! – anonymous