C#属性的数组表示法

6
使用JavaScript可以使用点符号或数组符号访问对象。
var myArray = {e1:"elem1",e2:"elem2",e3:"elem3",e4:"elem4"};
var val1 = myArray["e1"];
var val2 = myArray.e1;

是否可以使用C#来实现这个功能?

这是我的尝试:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection frmVals)
{
  string value;
  Owner owner = new Owner();

  foreach (var key in frmVals.AllKeys)
  {
    value = frmVals[key];
    owner[key] = value;  
  }
}

你为什么想要使用这种表示法? - Eric Giguere
1
不要这样做。也许有其他合法的情况,但这(一个ASP.NET MVC控制器操作)绝对不是其中之一。你真的真的非常想验证来自Web用户的输入。不要只是将任意值填充到任意命名的属性中。那只会引发安全问题。 - Robert Levy
感谢提供有用的信息。由于我是新手,我的想法是将输入值装入强类型对象中,如果值无法转换,则会引发异常。在填充值并且没有异常之后,我将验证属性值是否格式正确。在所有这些都经过验证之后,我可以将此对象传递给控件,它将保存到数据库中。 - deDogs
是的,你可以使用ExpandoObject在C# 4.0中实现,但是你不会在成员上获得智能感知。它基本上是一个实现IDictionary<string,object>的动态对象。 http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject(v=vs.100).aspx - BrainSlugs83
5个回答

6

虽然没有办法在C#中完全实现这一点,但您可以通过多种方式更改代码来达到目标。首先,您可以使用类似于以下内容的Dictionary:

var something = new Dictionary<string, object>() {
    { "property", "value"},
    { "property1", 1}
};
foreach (var keyVal in something) {
    var property = keyVal.Key;
    var propertyValue = keyVal.Value;
}

另一种选择是动态地执行:

dynamic somethingDyn = new System.Dynamic.ExpandoObject();
somethingDyn.property = "value";
somethingDyn.property1 = 1;

var somethingDynDict = (IDictionary<string, object>)somethingDyn;
var propValue = somethingDyn["property"];

foreach (var keyVal in somethingDynDict) {
    var property = keyVal.Key;
    var propertyValue = keyVal.Value;
}

如果您需要遍历强类型对象的属性,可以使用反射:

var owner = new Metis.Domain.User();
var properties = owner.GetType().GetProperties();
foreach (var prop in properties) {
    object value = prop.GetValue(owner, null);
}

字典方法不模仿该特性,因为它不提供属性样式的访问。 - Jeff Yates
1
我同意,但我认为重要的是他理解可用的选项,以便评估完成任务的最佳方式。使用字典方法可能比使用强类型对象更好。 - Nate Totten
我同意,我只是认为你需要注意它并不是与所描述的JavaScript功能一一对应的。 - Jeff Yates

3

我不建议这样做,但你可以在你的类中放置一个索引器,接受一个字符串,然后使用反射来读取该属性。类似于:

public object this[string key]
{
  get
  {
    var prop = typeof(ThisClassName).GetProperty(key);
    if (prop != null)
    {
      return prop.GetValue(this, null);
    }
    return null;
  }
  set
  {
    var prop = typeof(ThisClassName).GetProperty(key);
    if (prop != null)
    {
      prop.SetValue(this, value, null);
    }
  }
}

1

Javascript的数组表示法不适用于C#。

您需要使用点表示法来访问对象的成员。

您需要直接访问每个值并进行赋值:

owner.key = frmVals[key];
owner.key2 = frmVals[key2];

有一些解决方法 - 使用字典、动态对象甚至反射,但这种情况并不是 C# 直接支持的。


1

在C#中没有语法等价物,但有一些方法可以近似实现相同的功能。

您可以使用Dictionary来模拟索引器类型访问,但这样您将失去属性样式访问。对于属性样式访问,您可以在C#中使用匿名类型来实现类似的功能,例如:

var myType = new { e1="elem1",e2="elem2",e3="elem3",e4="elem4"};
var val1 = myType.e1;

然而,这并不创建一个数组或允许数组类型访问,也不允许在创建后修改类型。

为了更接近 JavaScript 的特性,您可以尝试使用 ExpandoObject 来模拟这个过程,或者自己实现一些东西。

为此,您需要一个类,该类具有构造函数,用于从传入的数组自动生成属性,并公开索引器,该索引器反过来使用反射查找命名属性。

这种类型的初始化可能是这样的:

var myType = new MyType(new[]{
    {"e1", "elem1"},
    {"e2", "elem2"},
    {"e3", "elem3"},
    {"e4", "elem4"}});

这假设每个元素定义都有一个子类型(可能使用 TupleKeyValuePair)。构造函数将采用该类型的 IEnumerable<T>


评论已删除,因为您比我更快地回答了问题。 - Ben Voigt
@Ben:感谢您的反馈。 - Jeff Yates

0

是的,这是可能的。

有两种可能性:

1)键和值列表是动态的。

  • 数组表示法由例如System.Collections.Generic.Dictionary<string, blah>提供
  • 成员访问表示法可以通过DLR魔术和dynamic关键字提供。

2)键和值列表是静态的。

  • C#编译器已经提供了成员访问表示法。
  • 使用反射可以获得数组表示法(希望使用缓存来提高性能)。

在静态情况下,成员访问表示法要快得多。在动态情况下,数组表示法会稍微快一些。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接