是否有更通用的方法来执行此类行为?
我们从 DataRow
进行大量打包和解包。是的,我们应该使用 ORM,但在那之前,这就是我们所拥有的。结果,有很多代码看起来像这样:
string username;
var temp = dr["Username"];
if (DbNull.Equals (temp))
{
username = "Anonymous";
} else {
username = dr["Username"].ToString();
}
最终,这成为一种模式并被翻译成辅助方法:
string username = StringExtensions.SafeParse (dr["Username"], "Anonymous");
这仍然很麻烦,并且需要各种原语的扩展方法。它还使代码变得混乱。我在 object
上创建了一个通用扩展方法,称为 As
。用法如下:
string username = dr["Username"].As<string> ("Anonymous");
这个相对简单的更改得到了其他开发人员的大力支持,并且在很多地方得到了使用。我不满意的部分是潜在的性能影响。 现在,我知道没有过早的优化。我编写的代码绝对没有任何过早的优化,并且它已经足够封装,因此事后对其进行优化应该不是什么大问题。我已经对该方法进行了基准测试,在我相对普通的 2GHz 工作站上每秒进行约二百五十万次转换,我必须承认,与它节省其他开发人员的时间和我们获得的可读性提升相比,这是惊人的性能。然而,考虑到下面的代码示例,我觉得我滥用了语言功能,而且还可以做得更好。该方法在 xmldoc 中包含“HERE BE DRAGONS”,以便大声喊叫!我正在寻找一种更好的方法来避免双重拳击。为简洁起见,我省略了实际版本,它在许多情况下实际上使用了 TryParse
。
public static TDestination As<TDestination> (this object source, TDestination defaultValue = default(TDestination))
{
if (source is TDestination)
return (TDestination) source;
if (source == null || DbNull.Equals(source))
return defaultValue;
if (TDestination is int)
return (TDestination) (object) Convert.ToInt32 (source.ToString ());
if (TDestination is long)
return (TDestination) (object) Convert.ToInt64 (source.ToString ());
if (TDestination is short)
return (TDestination) (object) Convert.ToInt16 (source.ToString ());
// and so on...
}
We do a lot of packing and unpacking from DataRow
. Yes, we should be using an ORM, but until then, this is what we've got. As a result of this, there is a lot of code that looks like this:
string username;
var temp = dr["Username"];
if (DbNull.Equals (temp))
{
username = "Anonymous";
} else {
username = dr["Username"].ToString();
}
Eventually, this became a pattern and was translated into helper methods:
string username = StringExtensions.SafeParse (dr["Username"], "Anonymous");
This is still cumbersome, and required extension methods for all kinds of primitives. It also clutters up the code. I created a generic extension method, on object
, called As<T>
. Usage looks like:
string username = dr["Username"].As<string> ("Anonymous");
This relatively simple change has been met with great aplomb with the other developers, and is getting used in a LOT of places. The part I'm unhappy with are potential performance implications. Now, I'm aware of no premature optimization. I definitely wrote the code without any premature optimization, and it's encapsulated enough that optimizing it afterwards shouldn't be a big deal. I've benchmarked the method to do about two and a half million conversions per second on my relatively modest 2GHz workstation, and I must admit this is phenomenal performance, compared to the time it saves other devs and the readability boost we gain. However, given the sample of code below, I feel like I'm misusing language features and it could be done much better. The method is xmldoc'ed with "HERE BE DRAGONS" for crying out loud! I'm looking for a better way to avoid the double-boxing. The actual version, which I've omitted for brevity, actually uses TryParse
in many instances.
public static TDestination As<TDestination> (this object source, TDestination defaultValue = default(TDestination))
{
if (source is TDestination)
return (TDestination) source;
if (source == null || DbNull.Equals(source))
return defaultValue;
if (TDestination is int)
return (TDestination) (object) Convert.ToInt32 (source.ToString ());
if (TDestination is long)
return (TDestination) (object) Convert.ToInt64 (source.ToString ());
if (TDestination is short)
return (TDestination) (object) Convert.ToInt16 (source.ToString ());
// and so on...
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
为什么不检查您的对象是否是 IConvertible,如果是,则使用 ToType:
Why not check if your object is IConvertible, and, if it is, use ToType:
根据问题中给出的示例
As
方法,您可以这样做:Based on the example
As
method given in your question, you could just do this instead:每当我进行反思或检查泛型类的
T
时,我都会使用字典Dictionary
。作为价值,我总是把每次应该做的事情作为Func
或Action
放入其中。在你的情况下,我可能会这样写:这种方法的唯一缺点是使用
object
导致(取消)装箱,如果经常重复调用该函数,这可能会导致一些性能问题在很短的时间内。但一如既往在提出要求之前先衡量。另一方面,添加更多转换器非常容易,并且由于字典的使用,您将始终是 O(1) 。
Whenever i goes into reflection or checking the
T
of my generic class i'm going to use a dictionaryDictionary<Type, ???>
. As value i always put something in that should be done for each time asFunc
orAction
. In your case i would write it maybe in that way:The only drawback of this approach that the usage of
object
leads to (un)boxing which maybe makes some performance problems if the function is called repeatedly for often in a very short time. But as always measure before claiming.On the other side it is quite easy to add further converter and you'll be always O(1) due to the usage of the dictionary.
如何为 datarow Field 属性定义一个扩展方法,您可以在其中提供与 Field 类型相同的自己的 null 值,如下所示:
How about defining an extension method for the datarow Field property where you can supply your own null value of the same type as the Field, like so:
我同意对 Field 函数进行变体是最好的方法,但如果您担心性能,则不要使用 IsNull() 或实际的 Field 函数,因为它们会执行大量冗余检查。以下方法就是您真正需要的。
这消除了发生额外装箱的需要,并且如果您小心使用 nullValue 参数,您通常可以不必在调用函数时显式指定 T。双赢。
I agree that making a variation of the Field function is the best way to go, but if you are concerned about performance then don't use IsNull() or the actual Field function as these perform a lot of redundant checking. The following method is all you really need.
This removes the need for additional boxing to occur and if you're careful with how you use the nullValue parameter you could generally forego having to specify T explicitly when calling the function. win-win.