C# 维护对象之间的一对一映射
我有以下两个类,它们提供了彼此之间的一对一映射。如何处理空值,当我运行第二个测试时,会出现stackoverflow异常。如何停止这个递归循环?谢谢C# 维护对象之间的一对一映射,c#,C#,我有以下两个类,它们提供了彼此之间的一对一映射。如何处理空值,当我运行第二个测试时,会出现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
[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;
}
}
}
}
}
你在这里遇到了无限循环 如果您只是不想得到
null
s,请使用以下方法:
get
{
if (_y == null)
_y = new Y();
return _y;
}
使用单独的实体存储对象之间的关系。像这样:
[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);
}
}
}
}
}
[TestFixture]
公共类测试员
{
[测试]
公共空间
{
var refs=新引用();
var x=新x(参考文献);
变量y=新的y(参考);
x、 Y=Y;
Assert.arame(x.Y,Y);
Assert.arame(y.X,X);
}
[测试]
public void SetYToNull()
{
var refs=新引用();
var x=新x(参考文献);
变量y=新的y(参考);
x、 Y=Y;
y、 X=零;
Assert.IsNull(x.Y);
Assert.IsNull(y.X);
}
}
公共类引用
{
私有IDictionary refs=新字典();
公共布尔包含(X,Y)
{
如果(!refs.ContainsKey(x))返回false;
如果(refs[x]!=y)返回false;
返回true;
}
公共作废删除(X X)
{
参考文献:移除(x);
}
公共无效添加(X,Y)
{
参考添加(x,y);
}
公共Y-Get(X X)
{
返回refs.ContainsKey(x)?refs[x]:空;
}
公共X得到(Y)
{
变量对=参考值,其中(r=>r.值==y);
返回pairs.Any()?pairs.FirstOrDefault().Key:null;
}
公共作废删除(Y)
{
X=Get(y);
如果(x!=null)
{
删除(x);
}
}
}
公共X类
{
私有只读参考文献;
公共X(参考文献)
{
this.refs=refs;
}
公共图书馆
{
get{return refs.get(this);}
设置
{
如果(值==null)
{
参考文献。删除(本);
}
其他的
{
如果(!refs.Contains(this,value))
{
参考添加(该值);
}
}
}
}
}
公共Y类
{
私人参考文献;
公共图书馆(参考文献)
{
this.refs=refs;
}
公共X X
{
get{return refs.get(this);}
设置
{
如果(值==null)
{
参考文献。删除(本);
}
其他的
{
如果(!refs.Contains(value,this))
{
参考添加(值,本);
}
}
}
}
}
工作正常:
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;
}
}
}
}
}
设置
y.X=null时代码>,它将尝试将y.X设置为null,因为X不是null,而这反过来又尝试将(y.X).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;
}
}
}
}
}
您想实现什么?当我将x.Y设置为null时,我希望x.Y和Y.x都为null,因为它们都相互引用,基本上我希望在两个对象之间保持双向引用。您可能希望重新考虑此设计。您可以删除此选项:if(temp!=null)
因为在setter开始时,您检查\ux!=值
,如果新值为null
,则temp变量始终不为null。看看我的答案。