如何从已转换为对象的匿名类型中获取数据?

时间:2011-03-13 00:54:01

标签: c#

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

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,所以我无法在ourtime函数中从中获取变量actionThink !有谁知道如何解决这个问题,或者如何以更好的方式做到这一点?

7 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

您可以使用反射:

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

答案 2 :(得分:1)

我摆脱了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 };
    }

答案 3 :(得分:1)

EDIT在此修正了一些细节。请参阅Matti Virkkunen的评论。

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

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

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

答案 4 :(得分:0)

我会编写一个包含两个属性的小类,并使用它而不是匿名类。另一个选择是切换到动态对象,并放弃类型安全。

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

答案 5 :(得分:0)

为什么不创建新类型

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) {         延迟[id] =新的DelayAction {ourtime = time + delay,action = a}; }

答案 6 :(得分:0)

我制作扩展方法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;
    }