防止未使用的属性从对象传递的最佳方法

4
我正在编写一个WCF服务,用于处理大型搜索(目前有50-60个参数,并且未来可能会添加更多)。为了处理这个问题,我创建了一个Search对象,其中包含所有的搜索条件,这些条件将在消息对象中传递给服务。虽然所有的搜索参数必须可用,但通常情况下只有2-3个参数接收用户输入,其他参数为空。在我看来,如果只使用几个字段,就没有必要在每个方法中传递整个对象。我正在寻找一种技术,可以提取使用的字段及其值,这些值可以进行验证并传递到数据层执行搜索。我能想到的几种实现方式包括:
  • 使用反射循环遍历属性,并将非空属性添加到Dictionary<string, object>中。这种方法的问题是,我失去了搜索参数的类型,这意味着数据层搜索函数将是一个巨大的case语句,其中包含每个潜在字段的硬编码转换值。这似乎有点过度设计,耦合性太强。
  • 创建一个SearchValue类,具有Name、Value和System.Type属性,并使用反射构建List<SearchValue>。这仍然会导致搜索中的大量case检查,但不是按属性而是按类型。这在使过程更“通用”(即独立于使用的搜索值的组合)方面具有一定吸引力,但这也感觉像是在重复造轮子。
我忽略了哪些技术的优缺点?有没有更好的方法来实现我的目标?
5个回答

0

有一个带有可选数据成员的DataContract类。

[DataMember(EmitDefaultValue = false)]

public int salary = 0;

DataContract序列化器在值为默认值时会忽略此类成员。

MSDN建议: 不建议将EmitDefaultValue属性设置为false。只有在特定需要,如互操作性或数据大小减小时才应这样做。

您还可以在DataMember中设置IsRequired属性为false,并使用EmitDefaultValue来帮助减少传输和序列化开销。


0
唯一的问题是在客户端和服务之间传递整个对象时可能存在的问题,当序列化请求中有太多空的 XML 节点时,会使其变得比必要的更大。你试图解决这个问题吗?我认为这并不是什么大问题,也不值得发明复杂的自定义机制。

这是我现在正在考虑的问题的下一部分 - 即使有逻辑的方法来做到这一点,哪一方更合理呢?正如你所指出的,许多空节点=比必要的请求更大,因此客户端更合适。缺点是将反射的开销移动到客户端而不是服务器上。另一方面,如果传递了完整的对象,那么在那时简化它是否有任何好处?有人认为在服务器端执行可以更容易地添加和删除参数。 - Clem

0

我不确定这是否适用于此线路通信,但可能是 DataMemberAttribute 上的 EmitDefaultValue 属性?


肯定有一种简单的方法来解决这个问题。这解决了我在其他评论中提到的“第二部分” - 这将删除客户端未使用的任何内容,简化了数据传输。那么我们回到了服务器端要做什么的问题 - 我应该不关心空字段,将SearchCriteria对象转储到数据层并让它解析出来吗?还是只提取非默认值字段并仅将其传递到数据层有任何好处? - Clem
我不确定你所说的ClientSide vs. Server Side是什么意思。实际上,这将使未使用的字段不会通过网络传输。假设客户端有合同,客户端只向服务发送“填充”的字段。然后,服务假定响应对象具有相同的标志,也会执行相同的操作。这不是你想要的吗(只需要非常少量且集成度高的努力)? - Brad Christie
EmitDefaultValue不会改变实际Search对象的结构,对吧?它只会改变通过网络传输的内容。所以当客户端将非默认值的数据发送到服务端时,会创建一个完整的Search对象,并将给定字段的数据传递过去,剩余字段使用默认值,是这样吗?它不会创建具有不同结构的Search对象...这对编程来说似乎是一场噩梦。 (续下) - Clem
所以如果我的理解是正确的,服务端可能会有一个搜索参数传入,然后在服务端将创建一个带有一个值和x个默认值的Search对象,这回答了我的最初问题。在将搜索请求发送到数据层之前,仅尝试提取那一个(或最小)数量的值是否有价值,或者在那一点上,放弃努力并将完整的Search对象转储到数据层进行解析是否更好? - Clem
据我所知,您正在为客户提供所有可搜索的参数。然后,他们可以自行决定使用其中任何一个或多个字段进行过滤,然后将其发送到服务器以相应地使用。现在,无论您是自己解析“相关”信息还是只让填充的字段通过网络传输,您仍然需要(在过滤时)检查哪些字段需要应用并实际应用它们。(续) - Brad Christie
这些值的字典没有任何用处,因为您仍然需要预见每个选项(无论是否提供)。我建议让服务层处理最小化流量的问题,您只需担心浏览所有属性并使用或忽略它们。这本质上就像使用空构造函数实例化对象一样,并且 .NET 使用空值填充它们(然后稍后使用接收到的数据填充已填充的字段)。 - Brad Christie

0

在你的第一点中,你提到使用Reflection将你的类型转换为Dictionary。而另一方面,为什么不编写一个反向逻辑,使用Reflection再次将Dictionary转换回你的类型呢?

示例:

客户端 > 你的类型 >>(Reflection)>> Dictionary > 通道 > Dictionary >>(Reflection)>> 你的类型 > 服务器端


0

我想到了几个选项:

  • 使用代码生成器将打包/解包代码创建为字典。生成器代码将使用反射,但打包/解包代码不会。

  • 将您的搜索类拆分为多个较小的类,然后让您的搜索类引用这些类。如果不使用这些搜索参数,则不要实例化子类。也许像这样:

    • 搜索
      • 包含一些公共字段的新类
      • 包含其他字段的新类

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接