使用。(点)运算符使用动态关键字得到字典值,这可能吗?

时间:2011-11-15 04:21:29

标签: c# .net variables arguments

我有以下课程:

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(), "..");
            }
        }
    }

我需要使用点operadotor获取字典的值,因为我将类设置为参数的类使用dynamic关键字在类上“走”。

例如:

 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的变量,将值..作为public类的foo成员。

无论如何要解决这个问题非常感谢。提前谢谢。

4 个答案:

答案 0 :(得分:7)

您可以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,您将失去类型安全性 - 您的用例应该能够证明这一缺点 - 通常有更好的方法。

答案 1 :(得分:4)

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

动态是这样的

// 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;
}

答案 2 :(得分:3)

如果您想直接公开Data成员,则另一个选择是使用ExpandoObject class,如您的示例所示。如果您不需要定义需要继承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”,尽管我也可以直接分配它:{​​{1}}。唯一的区别是您可能不知道您拥有的字段名称,前一个示例允许您根据动态输入设置foo.Data.d = "!",而后者在您已经知道要使用的字段名称时很有用

答案 3 :(得分:2)

在.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);