我有以下两个类,它们之间提供一对一的映射。我如何处理空值,当我运行第二个测试时,我得到一个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;
}
}
}
}
}
答案 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;
}
}
}
}
}
答案 1 :(得分:1)
当设置y.X = null;
时,会发生的事情是它会尝试将yX设置为null,因为_x不为null,而后者又尝试将(yX).Y设置为null,因为x中的_y仍然不为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;
}
}
}
}
}
答案 2 :(得分:0)
你在这里遇到无限循环。
如果您不想获得null
,请使用此选项:
get
{
if (_y == null)
_y = new Y();
return _y;
}
答案 3 :(得分: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);
}
}
}
}
}