【问题标题】:Can I get the default value for a null value removal expression in C#?我可以在 C# 中获取空值删除表达式的默认值吗?
【发布时间】:2019-01-19 16:44:57
【问题描述】:

鉴于dynamicobject,是否有办法在null 值移除的表达式中获取默认值?代码 sn-p 可能如下所示:

[Serializable]
public class Dynamico : DynamicObject, IDictionary<string, object>, ICloneable, INotifyPropertyChanged, IXmlSerializable
{
    private readonly IDictionary<string, object> _values = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

    public object this[string key]
    {
        get { return GetProperty(key); }
        set
        {
            _values[key] = value;
            OnPropertyChanged(key);
        }
    }

    public object GetProperty(string propertyName)
    {
        if (_values.ContainsKey(propertyName) == true)
        {
            return _values[propertyName];
        }
        return RequestProperty(propertyName);
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = GetProperty(binder.Name);
        **//To do: to get the default value of null value removal expression**
        return true;
    }

    public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
    {
        return base.TryInvoke(binder, args, out result);
    }
    ......
}

我可以使用下面的代码来使用class

dynamic obj = new Dynamico();
.......
var t = obj.DemoProp ?? "Default value is assigned";

我的问题是在Dynamicclass定义的TryGetMember方法中,如何获取默认值,即。 “分配了默认值”?解决方法可以使用表达式,有小伙伴可以推荐吗?

【问题讨论】:

    标签: c# expression


    【解决方案1】:

    感谢大家,为什么我需要实现这一点是因为我正在开发一个支持多模板的 CMS 引擎,它由 MVC 提供支持,我想让模板对开发人员友好,等等......(请原谅我跳过说来话长……)

    这里我想了个办法,把下面还没有优化的代码贴一下就行了。

    System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
    var frames = st.GetFrames();
    System.Diagnostics.StackFrame expfm = null;
    for (int i = 0; i < frames.Length; i++)
    {
        string fn = frames[i].GetMethod().Name;
        if (fn == "get_Item" || fn == "UpdateAndExecute1") // to find the caller
        {
            expfm = frames[i + 1];
            break;
        }
        else if (fn == "Execute")
        {
            expfm = frames[i];
            break;
        }
    }
    if (expfm != null)
    {
        var mb = expfm.GetMethod().GetMethodBody();
        byte[] il = mb.GetILAsByteArray();
        int offset = expfm.GetILOffset();
        bool found = false;
        for (int i = offset; i < il.Length && i <= offset + 100; i++)
        {
            if (il[i] == OpCodes.Brtrue_S.Value && il[i + 2] == OpCodes.Pop.Value && il[i + 3] == OpCodes.Ldstr.Value)
            {
                offset = i + 4;
                found = true;
                break;
            }
        }
        if (found)
        {
            int mt = ReadInt32(il, ref offset);
            var defs = expfm.GetMethod().Module.ResolveString(mt);
        }
    }
    
        private static int ReadInt32(byte[] il, ref int position)
        {
            return (((il[position++] | (il[position++] << 8)) | (il[position++] << 0x10)) | (il[position++] << 0x18));
        }
    

    变量'defs',包含我需要的默认值。

    【讨论】:

      【解决方案2】:

      你可以试试TryConvert:

      public override bool TryConvert(ConvertBinder binder, out object result)
      {
      
          if (binder.Type == typeof(String))
          {
              result = node.Value;
      
              return true;
          }
      
          else
          {
              result = null;
              return false;
          }
      }
      

      更多阅读:https://blogs.msdn.microsoft.com/csharpfaq/2009/10/19/dynamic-in-c-4-0-creating-wrappers-with-dynamicobject/

      【讨论】:

      • 感谢 Gauravsa。只是看了看试了一下。执行类型转换时似乎会调用 TryCovert,例如: object o = (Dynamico)obj;不能解决我的问题。
      【解决方案3】:

      这是不可能的,至少在你现在使用的语法中是不可能的。在表达式obj.DemoProp ?? "Default value is assigned" 中,隐式调用Dynamico.TryGetMember 的是对左侧操作数的求值,正如this question 的答案中所讨论的那样,C# 甚至不求值空合并的右侧操作数运算符 (??) 除非它确定左侧操作数为空。因此,"Default value is assigned" 的值(或您放置在其位置的任何表达式)不能用于通过评估 obj.DemoProp 调用的方法,因为它的值甚至尚未确定。

      如果您希望确定动态类中可能存在或不存在的属性值的同一逻辑也可以访问默认值,那么您必须提供专门用于该目的的方法,并依靠您的类的用户来调用该方法,而不是使用空合并运算符。例如,您可以编写obj.GetValueOrDefault("DemoProp", "Default value is assigned") 而不是obj.DemoProp ?? "Default value is assigned",然后将GetValueOrDefault 方法添加到Dynamico,它可以执行您想要执行的任何操作。祝你好运。

      【讨论】:

      • 谢谢乔。如果是真的,那就太可悲了。而我仍然想知道是否有一种方法可以获取调用 obj.DemoProp 的表达式(即 System.Linq.Expression),如果有,那么我只需要执行该表达式。或者通过 System.Diagnostics.StackTrace 类,我可以得到调用 obj.DemoProp 的方法,但它看起来像一个太大的代码块来做这个......卡住......
      • 我不认为这很可悲;这是 C# 的作者经过深思熟虑和明智的设计决定。即使你可以做你想做的事,我认为这将是一个坏主意。 C# 程序员习惯于编写像a ?? ba &amp;&amp; b 这样的表达式,并期望如果a 的值使得没有必要这样做,则永远不会计算b。你想要什么会使这种期望失效。
      猜你喜欢
      • 1970-01-01
      • 2020-09-02
      • 2010-11-26
      • 2011-03-23
      • 1970-01-01
      • 1970-01-01
      • 2015-02-04
      • 1970-01-01
      • 2013-04-01
      相关资源
      最近更新 更多