C#4.0,检测方法是否缺失

jus*_*ase 7 c# codedom dynamic

我有一种情况,我想将LinePragmas添加到CodeDom对象.但是一些代码dom对象具有LinePragma属性,而有些则没有.

所以我想知道是否可以使用dynamic关键字来检测对象上是否存在属性(不抛出异常),如果有,则添加pragma.这是我目前的方法:

public static T SetSource<T>(this T codeObject, INode sourceNode)
    where T : CodeObject
{
    codeObject.UserData["Node"] = sourceNode.Source;
    dynamic dynamicCodeObject = codeObject;

    // How can I not throw an exception here?
    if (dynamicCodeObject.LinePragma != null)
    {
        dynamicCodeObject.LinePragma = new CodeLinePragma(
        sourceNode.Source.Path.AbsoluteUri,
        sourceNode.Source.StartLine);
    }

    return codeObject;
}
Run Code Online (Sandbox Code Playgroud)

更新: 我使用的解决方案是添加一个名为Exists()的扩展方法.我在这里写了一篇关于它的博客文章: 成员存在动态C#4.0

jist是创建一个扩展方法,返回一个实现DynamicObject的TryGetMember的对象.它使用反射然后返回true或false.这允许你编写这样的代码:

object instance = new { Foo = "Hello World!" };
if (instance.Reflection().Exists().Foo)
{
    string value = instance.Reflection().Call().Foo;
    Console.WriteLine(value);
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*att 8

您可以检测对象是否具有属性而无需使用C#4.0的动态功能 - 而是使用已经存在一段时间的反射功能(我至少知道.NET 2.0,不确定<2.0)

PropertyInfo info = codeObject.getType().GetProperty(
    "LinePragma", 
    BindingFlags.Public | BindingFlags.Instance
)
Run Code Online (Sandbox Code Playgroud)

如果对象没有该属性,则GetProperty()将返回null.您可以对字段(GetField())和方法(GetMethod())执行类似操作.

不仅如此,一旦你拥有PropertyInfo,你可以直接使用它来做你的集合:

info.SetValue(codeObject, new CodeLinePragma(), null);
Run Code Online (Sandbox Code Playgroud)

如果您不确定该属性是否具有set方法,您可以采取更安全的路线:

MethodInfo method = info.GetSetMethod();
if(method != null)
    method.Invoke(codeObject, new object[]{ new CodeLinePragma() });
Run Code Online (Sandbox Code Playgroud)

这也为您提供了额外的好处,即在动态调用的查找开销上更加高效(无法找到该语句的引用,所以我只是将它浮出去).

我想这不是直接回答你的问题,而是实现同一目标的另一种解决方案.我还没有真正使用#4.0功能(尽管我是Ruby中动态类型的忠实粉丝).它当然不像动态解决方案那样干净/可读,但如果你不想抛出异常,它可能就是这样.

编辑:正如@a​​rbiter所指出的,"这仅对本机.net动态对象有效.例如,对于IDispatch,这不起作用."


flq*_*flq 5

我花了将近一个小时的时间来寻找获得某种红宝石式"RespondTo"方法的方法.肯定没有一个简单的答案,但我还没有放弃.

反思的观点应该是尝试的.

使用动态,我到目前为止唯一能做的就是将对象视为动态的扩展方法.如果它有效,它可以工作,如果没有它默默地失败...

public static void Dynamight<T>(this T target, Action<dynamic> action)
{
  dynamic d = target;
  try
  {
    action(d);
  }
  catch (RuntimeBinderException)
  {
    //That was that, didn't work out
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以......

string h = "Hello";
h.Dynamight(d => Console.WriteLine(d.Length)); //Prints out 5
h.Dynamight(d => d.Foo()); //Nothing happens
Run Code Online (Sandbox Code Playgroud)

更新:

因为我得到了downvotes和what-have-you让你比扩展方法的微妙命名更简洁:它是炸药(Geddit?)!吞噬异常并无所作为是不好的.这不是生产代码,而是概念证明的第1版.我一直忘记你不能在像stackoverflow这样的数千个论坛上微妙.Mea culpa.

  • 扩展方法仅吞下RuntimeBinderException,这是此方案中的所需行为.所有其他异常都会调出调用堆栈.我没有在这里看到问题. (2认同)