我正在使用WCF编写客户端和服务,但我怀疑目前存在多个问题。
从下面的代码中可以看出,该过程如下:客户端请求一些数据,服务生成并在DTO对象中返回。然后客户端尝试在返回的字典中进行查找,但这会引发KeyNotFoundException。
此外,服务器上的测试在此之前失败(如果没有注释),因为输入参数列表allBranches不再包含Branch currentBranch,它在方法调用的客户端执行。
有人可以告诉我这个代码中发生了什么,以及为什么它首先在服务器端爆炸,然后在客户端爆炸?
Shared class definitions
------------------------
[DataContract(IsReference = true)]
public class Branch
{
public Branch(int branchId, string name)
{
BranchId = branchId;
Name = name;
}
[DataMember]
public int BranchId { get; set; }
[DataMember]
public string Name { get; set; }
}
[DataContract]
public class Department
{
public string Name { get; set; }
// a few other properties, both primitives and complex objects
}
[DataContract]
public class MyDto
{
[DataMember]
public IDictionary<Branch, List<Department>> DepartmentsByBranch { get; set; }
[DataMember]
public Branch CurrentBranch { get; set; }
// lots of other properties, both primitives and complex objects
}
Server-side
--------------------------------
public CreateData(List<Branch> allBranches, Branch currentBranch)
{
// BOOM: On the server side, currentBranch is no longer contained in allBranches (presumably due to serialization and deserialization)
if (!branches.Contains(branchToOpen))
{
throw new ArgumentException("allBranches no longer contain currentBranch!");
}
// Therefore, I should probably not do the following, expecting to use currentBranch as a key in departmentsByBranch later on
var departmentsByBranch = branches.ToDictionary(branch => branch, branch => new List<Department>());
return new MyDto
{
DepartmentsByBranch = departmentsByBranch,
CurrentBranch = departmentsByBranch,
};
}
Client-side (relevant code only)
--------------------------------
var service = new ServiceProxy(); // using a binding defined in app.config
var allBranches = new List<Branch>
{
new Branch(0, "First branch"),
new Branch(1, "Second branch"),
// etc...
};
var currentBranch = allBranches[0];
MyDto dto = service.CreateData(allBranches, currentBranch);
var currentDepartments = dto.DepartmentsByBranch[currentBranch]; // BOOM: Generates KeyNotFoundException
编辑:我按照Jon在下面的优秀答案做了以下(解决了所有问题):
通过为每个属性提供私人设置器,使分支不可变。
实现了Object.Equals和GetHashCode的IEquatable +覆盖,后者按照这个SO答案(link)
实现IEquatable只需通过测试相等的属性值来完成,
public bool Equals(Branch other)
{
return other != null && ((BranchId == other.BranchId) && (Name == other.Name));
}
答案 0 :(得分:0)
您的代码失败的原因是您的客户端中有两个单独的Branch
实例:您在本地创建的实例(currentBranch
)以及从服务器接收并由WCF隐式创建的实例(在dto.DepartmentsByBranch
内)。你还没有指定这两个实例是#34;同样的东西&#34;,所以就字典而言,它从未见过你所说的currentBranch
。
您需要为Branch
提供IEquatable<Branch>
的正确实现 - 对于您用作字典键的所有类也是如此。
请注意&#34;正确实施&#34; means
如果您实施
IEquatable<T>
,您还应该覆盖基础Object.Equals(Object)
和GetHashCode
的类实现,以便 他们的行为与IEquatable<T>.Equals
的行为一致 方法