我的情况很简单。在我的代码中,我有这样的代码:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
//How to do this?
if (myVariable.MyProperty.Exists)
//Do stuff
因此,基本上我的问题是如何检查(不抛出异常)某个属性在我的动态变量上是可用的。我可以使用GetType(),但我宁愿避免这样做,因为我并不真正需要知道对象的类型。我真正想知道的是是否有一个属性(或方法,如果这使工作更简单的话)可用。指针吗?
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.
另一种解决方案是使用IDynamicMetaObjectProvider获取DLR看到的成员名。在下面的例子中,我使用一个静态类(Dynamic)来测试Age字段并显示它。
class Program
{
static void Main()
{
dynamic x = new ExpandoObject();
x.Name = "Damian Powell";
x.Age = "21 (probably)";
if (Dynamic.HasMember(x, "Age"))
{
Console.WriteLine("Age={0}", x.Age);
}
}
}
public static class Dynamic
{
public static bool HasMember(object dynObj, string memberName)
{
return GetMemberNames(dynObj).Contains(memberName);
}
public static IEnumerable<string> GetMemberNames(object dynObj)
{
var metaObjProvider = dynObj as IDynamicMetaObjectProvider;
if (null == metaObjProvider) throw new InvalidOperationException(
"The supplied object must be a dynamic object " +
"(i.e. it must implement IDynamicMetaObjectProvider)"
);
var metaObj = metaObjProvider.GetMetaObject(
Expression.Constant(metaObjProvider)
);
var memberNames = metaObj.GetDynamicMemberNames();
return memberNames;
}
}
如果你控制的类型被用作动态,你不能返回一个元组而不是每个属性访问的值吗?之类的……
public class DynamicValue<T>
{
internal DynamicValue(T value, bool exists)
{
Value = value;
Exists = exists;
}
T Value { get; private set; }
bool Exists { get; private set; }
}
可能是一个幼稚的实现,但如果您每次都在内部构造其中一个,并返回该值而不是实际值,那么您可以在每个属性访问上检查Exists,如果值为默认值(T),则单击value(如果不为默认值,则不相关)。
也就是说,我可能会遗漏一些动态工作原理的知识,这可能不是一个可行的建议。