测试动态变量上的属性是否可用
我的情况很简单。在我的代码中的某个地方,我有这样的内容:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
//How to do this?
if (myVariable.MyProperty.Exists)
//Do stuff
所以,基本上我的问题是如何检查(不引发异常)动态变量上的某个属性是否可用。我可以执行 GetType()
但我宁愿避免这样做,因为我实际上不需要知道对象的类型。我真正想知道的是某个属性(或方法,如果这能让生活更轻松)是否可用。有什么指点吗?
My situation is very simple. Somewhere in my code I have this:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
//How to do this?
if (myVariable.MyProperty.Exists)
//Do stuff
So, basically my question is how to check (without throwing an exception) that a certain property is available on my dynamic variable. I could do GetType()
but I'd rather avoid that since I don't really need to know the type of the object. All that I really want to know is whether a property (or method, if that makes life easier) is available. Any pointers?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
以防万一它对某人有帮助:
如果方法
GetDataThatLooksVerySimilarButNotTheSame()
返回一个ExpandoObject
,您也可以在检查之前转换为IDictionary
。Just in case it helps someone:
If the method
GetDataThatLooksVerySimilarButNotTheSame()
returns anExpandoObject
you can also cast to aIDictionary
before checking.两种常见的解决方案包括进行调用并捕获 RuntimeBinderException、使用反射检查调用,或者序列化为文本格式并从那里进行解析。异常的问题在于它们非常慢,因为当构造异常时,当前的调用堆栈被序列化。序列化为 JSON 或类似的东西会产生类似的惩罚。这给我们留下了反射,但只有当底层对象实际上是一个具有真实成员的 POCO 时,它才有效。如果它是字典、COM 对象或外部 Web 服务的动态包装器,那么反射将无济于事。
另一种解决方案是使用
IDynamicMetaObjectProvider
获取 DLR 看到的成员名称。在下面的示例中,我使用静态类 (Dynamic
) 来测试Age
字段并显示它。The two common solutions to this include making the call and catching the
RuntimeBinderException
, using reflection to check for the call, or serialising to a text format and parsing from there. The problem with exceptions is that they are very slow, because when one is constructed, the current call stack is serialised. Serialising to JSON or something analogous incurs a similar penalty. This leaves us with reflection but it only works if the underlying object is actually a POCO with real members on it. If it's a dynamic wrapper around a dictionary, a COM object, or an external web service, then reflection won't help.Another solution is to use
IDynamicMetaObjectProvider
to get the member names as the DLR sees them. In the example below, I use a static class (Dynamic
) to test for theAge
field and display it.Denis 的回答让我想到了使用 JsonObjects(
标头属性检查器)的另一种解决方案:
或者可能更好:
例如:
Denis's answer made me think to another solution using JsonObjects,
a header property checker:
or maybe better:
for example:
好吧,我在单元测试中遇到了类似的问题。
使用 SharpTestsEx 您可以检查属性是否存在。我用这个测试我的控制器,因为由于 JSON 对象是动态的,有人可能会更改名称并忘记在 javascript 或其他内容中更改它,因此在编写控制器时测试所有属性应该会提高我的安全性。
示例:
现在,使用 SharTestsEx:
使用此功能,我使用“Should().NotThrow()”测试所有现有属性。
它可能超出主题,但对某人可能有用。
Well, I faced a similar problem but on unit tests.
Using SharpTestsEx you can check if a property existis. I use this testing my controllers, because since the JSON object is dynamic, someone can change the name and forget to change it in the javascript or something, so testing for all properties when writing the controller should increase my safety.
Example:
Now, using SharTestsEx:
Using this, i test all existing properties using "Should().NotThrow()".
It's probably out of topic, but can be usefull for someone.
根据 @karask 的回答,您可以将该函数包装为助手,如下所示:
Following on from the answer by @karask, you could wrap the function as a helper like so:
对我来说这有效:
For me this works:
如果您控制用作动态的类型,难道您不能为每个属性访问返回一个元组而不是一个值吗?类似...
可能是一个幼稚的实现,但如果您每次在内部构造其中一个并返回它而不是实际值,您可以在每个属性访问上检查
Exists
,然后点击如果存在,则值为
default(T)
(并且不相关),如果不存在,则值为default(T)
(且不相关)。也就是说,我可能缺少一些关于动态如何工作的知识,这可能不是一个可行的建议。
If you control the type being used as dynamic, couldn't you return a tuple instead of a value for every property access? Something like...
Possibly a naive implementation, but if you construct one of these internally each time and return that instead of the actual value, you can check
Exists
on every property access and then hitValue
if it does with value beingdefault(T)
(and irrelevant) if it doesn't.That said, I might be missing some knowledge on how dynamic works and this might not be a workable suggestion.
如果您的用例是转换 api 响应,仅携带几个字段,您可以使用:
If your use case is to convert an api response, carrying about only a few fields, you can use this:
您可以首先将其转换为
JObject
并使用.ContainsKey()
函数检查属性是否存在。JObject
位于Newtonsoft.Json.Linq
命名空间中You could first covert it to a
JObject
and use the.ContainsKey()
function to check if a property exists.JObject
is found in theNewtonsoft.Json.Linq
namespace这是另一种方式:
Here is the other way:
就我而言,我需要检查是否存在具有特定名称的方法,因此我为此使用了一个接口
此外,接口可以包含的不仅仅是方法:
来自:接口(C# 编程指南)
优雅不需要捕获异常或玩反射......
In my case, I needed to check for the existence of a method with a specific name, so I used an interface for that
Also, interfaces can contain more than just methods:
From: Interfaces (C# Programming Guide)
Elegant and no need to trap exceptions or play with reflexion...
我知道这确实是旧帖子,但这里有一个在
c#
中使用dynamic
类型的简单解决方案。I know this is really old post but here is a simple solution to work with
dynamic
type inc#
.由于
ExpandoObject
继承了IDictionary
您可以使用以下检查您可以创建一个实用方法来执行此检查,这将使代码更加清晰和重新-可用
As
ExpandoObject
inherits theIDictionary<string, object>
you can use the following checkYou can make a utility method to perform this check, that will make the code much cleaner and re-usable
我认为,除非您重新实现 C# 编译器中处理动态绑定的方式,否则无法在不尝试访问动态变量的情况下找出它是否具有某个成员。这可能会包含很多猜测,因为根据 C# 规范,它是实现定义的。
因此,您实际上应该尝试访问该成员并捕获异常(如果失败):
I think there is no way to find out whether a
dynamic
variable has a certain member without trying to access it, unless you re-implemented the way dynamic binding is handled in the C# compiler. Which would probably include a lot of guessing, because it is implementation-defined, according to the C# specification.So you should actually try to access the member and catch an exception, if it fails:
我想我应该对 Martijn 的答案 和 svick 的回答...
以下程序返回以下结果:
因此我建议使用反射。见下文。回应 bland 的评论:
比率是 100000 次迭代的
reflection:exception
刻度:...足够公平 - 如果您预计它失败的概率小于 ~1/47,那么就选择例外。
上面假设您每次都运行
GetProperties()
。您可以通过在字典或类似内容中缓存每种类型的GetProperties()
结果来加快该过程。如果您反复检查同一组类型,这可能会有所帮助。I thought I'd do a comparison of Martijn's answer and svick's answer...
The following program returns the following results:
As a result I'd suggest using reflection.See below.Responding to bland's comment:
Ratios are
reflection:exception
ticks for 100000 iterations:...fair enough - if you expect it to fail with a probability with less than ~1/47, then go for exception.
The above assumes that you're running
GetProperties()
each time. You may be able to speed up the process by caching the result ofGetProperties()
for each type in a dictionary or similar. This may help if you're checking against the same set of types over and again.也许使用反射?
Maybe use reflection?