【问题标题】:How do I get data from an anonymous type that's been converted to an object?如何从已转换为对象的匿名类型中获取数据?
【发布时间】:2015-05-26 23:04:59
【问题描述】:

我正在创建一个延迟函数管理器,以便您可以调用TimeManager.DelayedCall(uniqueid, delay, action) 以使actiondelay 秒内被调用。但是,我遇到了一些麻烦。这是到目前为止的代码。

private static Dictionary<string, object> delays = new Dictionary<string, object>();

public static void Think(float dt)
{
        timestep = dt * timescale;

        time += timestep;

        foreach (KeyValuePair<string, object> kv in delays)
        {
            if (time > kv.Value.ourtime)
            {
                kv.Value.action();
            }
        }
}

public static void DelayedCall(string id, float delay, Action a)
{
        delays[id] = new { ourtime = time + delay, action = a };
}

此代码无法编译。因为我将匿名类型从DelayedCall 函数转换为object,所以我无法在Think 函数中从中获取变量ourtimeaction!有谁知道如何解决这个问题,或者如何以更好的方式做到这一点?

【问题讨论】:

    标签: c#


    【解决方案1】:

    编辑在这里更正了一些细节。请参阅下面 Matti Virkkunen 的评论。

    您的匿名类型仅在您创建它的方法中具有作用域。您无法在 think 函数中获取属性,因为一旦将其转换为对象 并将其保存在字典中,您设置的属性就消失了。 您无法将其转换回由编译器,因此您无法访问您设置的属性,除非通过反射间接访问。

    为什么你需要使用匿名类型和对象类型呢?

    根据发布的代码,我将创建一个 DelayData 对象,该对象具有您需要设置的所有属性,在字典中创建和存储 DelayData 实例,然后直接从字典中使用该对象。

    【讨论】:

    • 抱歉,我又发了一篇同样的帖子——我开始打字时没有答案。
    • 就是这样。最清晰的帖子通常会赢得奖品,而不是最快的帖子。
    • 我想我懒得为此单独开设一个课程,但我想我现在必须这样做!干杯!
    • 属性没有“消失”。转换一个对象只会改变你对它的当前引用类型,并且不会以任何方式改变它。这些属性仍然可以通过dynamic 或反射访问,尽管这样会失去类型安全性。
    • 谢谢,我在回答中解决了这个问题。
    【解决方案2】:

    嗯...您总是可以使用反射来访问对象中的字段,但这很慢,并且可能很难看(尽管最后一点是主观的)。更简洁的版本将涉及动态对象(但您会失去类型安全性)。

    但是为什么你必须绝对使用匿名类型呢?你不能只写一个小包装 classstruct,然后在你的字典中使用它而不是 object 吗?

    【讨论】:

      【解决方案3】:

      你可以使用反射:

      Action a = () => { Console.Write("Hello"); };
      object o = new { ourtime = DateTime.Now, action = a };
      
      DateTime ourtime = (DateTime) o.GetType().GetProperties()[0].GetValue(o, null);
      Action action = (Action) o.GetType().GetProperties()[1].GetValue(o, null) ;
      

      但是创建一个新类型来保存这些值会更简洁,即TimedAction 具有两个属性TimeAction

      【讨论】:

        【解决方案4】:

        我会摆脱 AnonymousType。它只会使事情变得不清楚,并且可能会通过添加错误的类型来混淆字典中的值。我还添加了一些Linq,以及List.ForEach的使用。

        public class Thing
        {
            public double ourtime;
            public Action action;
        }
        
        public class Program
        {
            private readonly Dictionary<string, Thing> delays = new Dictionary<string, Thing>();
        
            public void Think(float dt)
            {
                timestep = dt * timescale;
        
                time += timestep;
        
                var actions = delays.Where(d => time > d.Value.ourtime).Select(d => d.Value.action).ToList();
                actions.ForEach(a => a());
            }
        
            public void DelayedCall(string id, float delay, Action a)
            {
                delays[id] = new Thing { ourtime = time + delay, action = a };
            }
        

        【讨论】:

          【解决方案5】:

          我会编写一个具有两个属性的小类并使用它来代替匿名类。另一种选择是切换到动态对象,并放弃类型安全。

          http://msdn.microsoft.com/en-us/library/dd264736.aspx

          【讨论】:

            【解决方案6】:

            为什么不创建一个新类型

            class DelayAction
            {
                float OurTime;
                Action a;
            }
            

            改成

            private static Dictionary<string, DelayAction> delays = new Dictionary<string, DelayAction>();
            

            public static void DelayedCall(string id, float delay, Action a) { delays[id] = new DelayAction{ ourtime = time + delay, action = a }; }

            【讨论】:

              【解决方案7】:

              我制作扩展方法 ToDictionary

              object anonymous = new
              {
                  Id = 1234,
                  Password = "pwd",
              };
              
              var dictionary = anonymous.ToDictionary();
              

              扩展方法如下。

                  public static IDictionary<string, dynamic> ToDictionary<T>(this T target, bool exceptDefaultValue = false)
                      where T : class
                  {
                      if (target == null)
                      {
                          throw new ArgumentNullException("target");
                      }
              
                      IDictionary<string, dynamic> dictionary = new Dictionary<string, dynamic>(System.StringComparer.OrdinalIgnoreCase);
              
                      foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(target))
                      {
                          object value = propertyDescriptor.GetValue(target);
              
                          if (exceptDefaultValue == true)
                          {
                              if (value == null || value.Equals(propertyDescriptor.PropertyType.DefaultValue()) == true)
                              {
                                  continue;
                              }
                          }
              
                          dictionary.Add(propertyDescriptor.Name, value);
                      }
              
                      return dictionary;
                  }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-29
                • 1970-01-01
                • 1970-01-01
                • 2010-11-27
                • 1970-01-01
                相关资源
                最近更新 更多