【问题标题】:Intercept a dynamic call to avoid RuntimeBinderException拦截动态调用以避免 RuntimeBinderException
【发布时间】:2016-01-20 13:12:36
【问题描述】:

当调用的方法或属性不存在时,我想拦截对动态类型的调用以避免 RuntimeBinderException。 例如:

class Foo {
    bool IsFool{ get; set; }
}
...
dynamic d = new Foo();
bool isFool = d.IsFoo; //works fine
bool isSpecial = d.IsSpecial; //RuntimeBinderException

我想要做的是要么在调用时创建不存在的属性,要么只返回 null。

编辑:我正在尝试做的项目是一个配置文件阅读器。所以我希望避免尝试捕获或检查配置文件的每个属性是否存在。

【问题讨论】:

    标签: c# dynamic runtimeexception


    【解决方案1】:

    除了在try .. catch 块中处理之外,我没有看到任何特殊的方法

    try 
    {
      bool isSpecial = d.IsSpecial;
      return isSpecial;
    }
    catch(RuntimeBinderException)
    {
      // do something else
      return false;
    }
    

    (或)使用 System.Reflection 命名空间

            bool isSpecial = typeof(Foo)
                             .GetProperties()
                             .Select(p => p.Name == "IsSpecial").Count() > 0 
                             ? d.IsSpecial : false;
    

    根据您在帖子中的编辑;不确定这有多优雅,但您可以在 App.ConfigWeb.Config 文件中定义一个 AppSetting 元素,例如

    <configuration>
      <appSettings>
        <add key="IsFool" value="Foo"/>
        <add key="Display" value="Foo"/>
      </appSettings>
    </configuration>
    

    然后可以读取它来验证成员是否存在,然后相应地调用

            dynamic d = new Foo();
    
            bool isSpecial = System.Configuration.ConfigurationManager.AppSettings
                             .AllKeys.Contains("IsSpecial") 
                             ? d.IsSpecial : false;
    

    【讨论】:

    • 谢谢,但是这种方式违背了让代码更容易编写和阅读的主要目的。
    • @dcidral,提出了两种选择;使用try .. catch 块或使用反射。请参阅答案中的编辑。
    • @dcidral,如果有帮助,请检查答案中的编辑。
    • 嗨@rahul。我感谢您的帮助,很抱歉没有更清楚。我以各种方式读取配置文件没有问题。我想要创建一个项目,使这个过程更干净,更易于在其他几个项目中使用。所以问题在于拦截对动态变量的调用。要读取配置文件,我已经有一个使用类似的类: var configValue = config["config_name"].Value;但我想做这样的事情:var configValue = config.config_name;
    【解决方案2】:

    异常通常需要很长时间尝试检查属性是否存在:

    public static bool HasProperty(this object obj, string propertyName)
    {
        return obj.GetType().GetProperty(propertyName) != null;
    }
    

    【讨论】:

      【解决方案3】:

      在这里找到答案:https://stackoverflow.com/a/1110504/818088
      我必须扩展DynamicObject 并覆盖TryInvokeMember

      【讨论】:

        【解决方案4】:

        最简单的方法是将其转换为 JSON 动态对象:

        public static class JsonExtensions
        {
            public static dynamic ToJson(this object input) => 
                 System.Web.Helpers.Json.Decode(System.Web.Helpers.Json.Encode(input));
        
            static int Main(string[] args) {
                 dynamic d = new Foo() { IsFool = true }.ToJson();
                 Console.WriteLine(d.IsFool); //prints True
                 Console.WriteLine(d.IsSpecial ?? "null"); //prints null
            }
        }
        
        class Foo
        {
            public bool IsFool { get; set; }
        }
        

        【讨论】:

          猜你喜欢
          • 2017-04-07
          • 2010-11-22
          • 2011-02-04
          • 1970-01-01
          • 2018-04-17
          • 2016-12-03
          • 1970-01-01
          • 2014-09-27
          • 2015-06-26
          相关资源
          最近更新 更多