这是泛型和 C# 动态数据类型的适当使用吗?
因此,我遇到的问题是,我们正在使用现有的 ORM(这是一个名为 Gentle 的旧版本)构建一个数据访问层,并考虑转向 Fluent NHibernate 之类的东西。有一些查询,我们必须在现有设置中向 SqlBuilder 添加自定义子句,因此,例如,在检索某些人员对象时,我们可能会添加如下子句:
"PersonId in (SELECT PersonId from Orders where OrderValue > " + orderValue + " and OrderName = " + orderName
要点是参数直接添加到字符串中,而不是直接添加到字符串中。与作为参数化查询相比,在 Gentle 中可以将其添加为参数化查询,这就是我一直在努力的方向。我们所有的 DAL 都继承自一个基 GentleDAL
,这是实际构造 Gentle 查询、添加子句和参数等的类。要在 Gentle 中添加参数化子句,您必须使用 SqlBuilder 做两件事对象,您必须调用 sb.AddConstraint(string Clause) 来添加您的子句,然后对于每个参数,您必须调用 sb.AddParameter(string name, Type type),然后您可以从中构造您的 SqlStatement
对象,只有在此之后您才能在调用 stmt.SetParameter(string name, object) 时设置参数的值值)
。
我表示这些参数/子句的方式是创建一个名为 GentleClauseCollection 的类,它包含子句和参数,并具有用于这两个内容的 Add 和 Get 方法。子句只是字符串,内部存储在列表中,参数存储在使用泛型的 GentleParameter 类中。 GentleParameter的完整代码如下。
public class GentleParameter<TParamType>
{
public string Name { get; private set; }
public TParamType Value { get; private set; }
public Type ParameterType {get { return typeof (TParamType); }}
public GentleParameter(string parameterName, TParamType parameterValue)
{
Name = parameterName;
Value = parameterValue;
}
}
据我所知,.NET 中没有任何集合可以让我在同一集合中存储不同 TParamType 值的 GentleParameter,但可以使用 DLR 来完成。在我的 GentleCollection 类中,我将参数存储在列表中,并从此类中以 IEnumerable 形式获取参数。我的类中的 Add 方法只能允许添加 GentleParameter,因此我知道我的参数将始终具有我可以访问的名称、值和 ParameterType 字段。
我的问题是:鉴于我可以牺牲泛型并将参数类 Value 属性更改为“对象”而不是 T,我是否通过使用动态使事情变得过于复杂,这两种方法的优点和缺点是什么?是否有第三种方法可以做到这一点,我没有想到,并且考虑到使用动态对象的所有方法调用都将在运行时进行编译,使用动态可能会对性能产生多大的影响?
预先感谢您的帮助。
The problem I'm having is thus, we're building a data access layer using our existing ORM (it's an old one called Gentle) with the idea of moving to something like Fluent NHibernate. There are a few queries where we have to add custom clauses to the SqlBuilder in our existing setup, so for instance when retrieving some person objects we might be adding a clause like:
"PersonId in (SELECT PersonId from Orders where OrderValue > " + orderValue + " and OrderName = " + orderName
The point being that the parameters are being added directly in a string rather than as a parameterised query, it is possible in Gentle to add it as a parameterised query and this is what I've been working on. All our DALs inherit from a base GentleDAL
, this is the class that actually constructs the Gentle query, adds the clauses and parameters etc. To add a parameterised clause in Gentle you have to do two things with your SqlBuilder object, you have to call sb.AddConstraint(string clause)
to add your clause, and then for each parameter you have to call sb.AddParameter(string name, Type type)
, you can then construct your SqlStatement
object from this, and only after that can you set the value for your parameter where you call stmt.SetParameter(string name, object value)
.
The way I have represented these parameters/clauses is I have created a class called GentleClauseCollection, this contains the clauses and parameters and has Add and Get methods for both of these things. Clauses are just strings and are stored internally in a List, the parameters are stored in a GentleParameter class which uses generics. The full code for GentleParameter is as follows.
public class GentleParameter<TParamType>
{
public string Name { get; private set; }
public TParamType Value { get; private set; }
public Type ParameterType {get { return typeof (TParamType); }}
public GentleParameter(string parameterName, TParamType parameterValue)
{
Name = parameterName;
Value = parameterValue;
}
}
There is no collection in .NET that I'm aware of that would let me store GentleParameter for different values of TParamType in the same collection, however it can be done using the DLR. In my GentleCollection class I store the parameters in a List and I get the parameters from this class as an IEnumerable. The Add method in my class is able to only allow GentleParameter's to be added so I know that my parameters will always have a Name, Value and ParameterType field which I can access.
My questions are: Given I could sacrifice the generics and change my parameter class Value property to be 'object' instead of T, have I overcomplicated things by using dynamic, what are the pros and cons of both approaches? Is there a third way to do this that I haven't thought of and how significant a performance impact am I likely to see by using dynamic given that all the method calls using the dynamic objects will be compiled at run time?
Thanks in advance for your help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
由于 sb.SetParameter 不是通用的并且等待对象,因此我不会将 GentleParameter 设为通用,因此我不会使用 DLR。
As
sb.SetParameter
is not generic and awaits anobject
, I would not makeGentleParameter
generic and hence I would not use the DLR.使用动态对我来说似乎并不复杂。方法调用在运行时解析并缓存,结果调用可能平均慢 10 倍(我们说的是纳秒)。因此,如果有意义的话,这取决于您将如何使用它。
如果您总是将其用作
Object
类型,那么您不需要使用动态类型,因为它不会伤害任何东西。如果您希望能够访问属性,那么您应该使用动态,结果代码看起来比您可以做的任何其他事情都更干净。
但即使使用动态,您也不一定必须动态调用属性本身,如果您想要尽可能多的静态类型,您可以动态解析一个辅助方法,该方法采用 GentleParameter 的通用形式,并在其中完成工作。
Using dynamic doesn't seem over complicated to me. Method calls are resolved at runtime and it's cached the resulting invocation probably averages about 10x slower (we are talking nanoseconds). So it depends on how you are going to use it if it makes sense.
If you are always going to use it as type
Object
than yes you don't need to be using type dynamic not that it would have hurt anything.If you want to be able to access properties than yes you should use dynamic, the result code will look cleaner than anything else you could do.
But even using dynamic you don't necessarily have to call the properties themselves dynamically, if you want to have as much static typing is possible you can have dynamic resolve a helper method that takes a generic form of your GentleParameter and do your work inside that.