使用动态关键字使用.(点)运算符获取字典值,这是可能的

本文关键字:获取 关键字 动态 运算符 字典 | 更新日期: 2023-09-27 18:14:43

我有以下类:

public class foo
    {
        public Dictionary<string, string> data = new Dictionary<string, string>();
        public foo(params object[] args)
        {
            foreach (object arg in args)
            {
                data.Add(arg.ToString(), "..");
            }
        }
    }

我需要使用点操作符获得字典的值,这是因为我将类设置为参数的类使用动态关键字在类上"行走"。

例如:

 var args = new[] {"a","b","c"};
 var Foo = new foo(args);
 var baa = Foo.data.a;
 Console.Write(baa); // .. 

存在一种创建动态变量的方法,例如:

public foo(params object[] args) {
foreach (object arg in args) {
  var name = (string) arg;
  var value = "..";
  MakeVariable(name, value);  
}
}

将变量命名为arg,并将值..作为publicfoo类中的成员。

以不同的方式解决这个问题是非常赞赏的。

使用动态关键字使用.(点)运算符获取字典值,这是可能的

可以让Foo继承DynamicObject:

public class Foo : DynamicObject
{
    private Dictionary<string, string> data = new Dictionary<string, string>();
    public Foo(params object[] args)
    {
        foreach (object arg in args)
        {
            data.Add(arg.ToString(), "..");
        }
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (data.ContainsKey(binder.Name))
        {
            result = data[binder.Name];
            return true;
        }
        return base.TryGetMember(binder, out result);
    }
}

可以使用dynamic来保存Foo的实例:

var args= new[] { "a", "b", "c" };
dynamic foo = new Foo(args);
var myA = foo.a; //returns ".."

请记住,由于必须使用dynamic,您将失去类型安全性-您的用例应该真正证明这个缺点-通常有更好的方法。

我认为你应该使用DynamicObject。如果你使用的是旧版本的框架,唯一的选择是Reflection。发出

动态的工作原理是这样的

// If you try to get a value of a property 
// not defined in the class, this method is called.
public override bool TryGetMember(
    GetMemberBinder binder, out object result)
{
    // Converting the property name to lowercase
    // so that property names become case-insensitive.
    string name = binder.Name.ToLower();
    // If the property name is found in a dictionary,
    // set the result parameter to the property value and return true.
    // Otherwise, return false.
    return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(
    SetMemberBinder binder, object value)
{
    // Converting the property name to lowercase
    // so that property names become case-insensitive.
    dictionary[binder.Name.ToLower()] = value;
    // You can always add a value to a dictionary,
    // so this method always returns true.
    return true;
}

如果您想要直接公开Data成员,另一个选择是使用ExpandoObject类,如您的示例中所示。如果您不需要定义需要继承DynamicObject的特定操作,这将使代码更简单。

public class Foo
{
    public dynamic Data = new ExpandoObject();
    public Foo(params object[] args)
    {
        var dataDict = (IDictionary<string, object>)Data;
        foreach (var obj in args)
        {
            dataDict.Add(obj.ToString(), "..");
        }
    }
}

用法:

var foo = new Foo("a", "b", "c");
Console.WriteLine(foo.Data.a);    
((IDictionary<string, object>)foo.Data).Add("d", "!");
foreach (var item in foo.Data)
{
    Console.WriteLine("{0} : {1}", item.Key, item.Value);
}

注意,我转换到一个字典并添加了"d",尽管我也可以直接赋值:foo.Data.d = "!"。唯一的区别是,您可能事先不知道您有什么字段名,前一个示例允许您基于动态输入设置ExpandoObject,而后一个示例在您已经知道要使用的字段名时很有用。

在。net 4中,这个确切的行为是由ExpandoObject类实现的:

public class Foo
{
    private readonly ExpandoObject _dict = new ExpandoObject();
    public dynamic Data
    {
        get { return _dict; }
    }
    public Foo(params object[] args)
    {
         foreach (var arg in args)
             _dict.Add(arg.ToString(), "..");
    }
}
var foo = new Foo("a", "b", "c");
foo.Data.x = 3.14;
Console.Write(foo.Data.a);