【问题标题】:Accessing object property as string and setting its value以字符串形式访问对象属性并设置其值
【发布时间】:2011-02-23 17:07:42
【问题描述】:

我有一个Account 类的实例。每个帐户对象都有一个所有者、引用等。

我可以访问帐户属性的一种方法是通过像

这样的访问器
account.Reference;

但我希望能够使用动态字符串选择器来访问它,例如:

account["PropertyName"];

就像在 JavaScript 中一样。所以我会拥有account["Reference"],它会返回该值,但我也希望能够在此之后分配一个新值,例如:

account["Reference"] = "124ds4EE2s";

我注意到我可以使用

DataBinder.Eval(account,"Reference") 

基于字符串获取属性,但使用它我无法为属性赋值。

知道我该怎么做吗?

【问题讨论】:

  • 你的意思是“C#”,不是吗,不是“csharp”?
  • C# 不是脚本语言;通常在学习一门新语言时;您需要学习随之而来的新习语和惯例。

标签: c# string eval accessor databinder


【解决方案1】:

首先,你应该避免使用这个; C# 是一种强类型语言,因此请利用伴随该方面的类型安全和性能优势。

如果您有正当理由动态获取和设置属性的值(换句话说,当无法在代码中定义类型和/或属性名称时),那么您必须使用反射。

最内联的方式是这样的:

object value = typeof(YourType).GetProperty("PropertyName").GetValue(yourInstance);
...
typeof(YourType).GetProperty("PropertyName").SetValue(yourInstance, "value");

但是,您可以缓存 PropertyInfo 对象以使其更具可读性:

System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");

object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");

【讨论】:

  • 有人告诉我 C# 的类型太强了。经过一番思考,我认为这还不算太糟糕。
  • 您可以使用它来节省大量编码(以及更少的代码=更少的错误)以实现持久性。像 ruby​​ 一样使用它,让你的数据库表匹配你的属性并专注于算法,而不是无休止的打字(强键和键盘)
【解决方案2】:

你需要使用反射:

PropertyInfo property = typeof(Account).GetProperty("Reference");

property.SetValue(myAccount, "...", null);

请注意,这会很慢。

【讨论】:

    【解决方案3】:

    如果它们是您自己的对象,您可以提供一个索引器来访问这些字段。我真的不推荐这个,但它会满足你的需求。

    public object this[string propertyName]
    {
        get
        {
            if(propertyName == "Reference")
                return this.Reference;
            else
                return null;
        }
        set
        {
            if(propertyName == "Reference")
                this.Reference = value;
            else
                // do error case here            
        }
    }
    

    请注意,这样做会失去类型安全性。

    【讨论】:

      【解决方案4】:

      我同意之前的海报,您可能确实需要使用这些属性。与直接访问属性相比,反射非常慢。

      另一方面,如果您需要维护用户定义属性的列表,则不能使用 C# 属性。你需要假装你是Dictionary,或者你需要暴露一个行为类似于Dictionary 的属性。下面是一个示例,说明如何使 Account 类支持用户定义的属性:

      public class Account
      {
          Dictionary<string, object> properties;
          public object this[string propertyName]
          {
              get
              {
                  if (properties.ContainsKey[propertyName])
                      return properties[propertyName];
                  else
                      return null;
              }
              set
              {
                  properties[propertyName] = value;
              }
          }
      }
      

      【讨论】:

      • 这正是我所需要的。就我而言,有几个数字属性需要按名称访问。所以我使用Dictionary&lt;string, float&gt; properties; 作为支持字段。此外,实际上定义了每个属性。因此可以通过Account.PropertyXAccount["PropertyX"] 访问属性。
      【解决方案5】:

      您可以尝试将索引器与反射相结合...

      public object this[string propertyName]
      {
          get
          {
              PropertyInfo property = GetType().GetProperty(propertyName);
              return property.GetValue(this, null);
          }
          set
          {
              PropertyInfo property = GetType().GetProperty(propertyName);
              property.SetValue(this,value, null);
          }
      }
      

      【讨论】:

      • +1 也适用于我。请注意,您需要处理可能为 null 的属性。
      【解决方案6】:

      我个人更喜欢使用扩展方法,所以这是我的代码:

      public static class ReflectionExtensions
      {
          public static void SetPropertyValue(this object Target,
              string PropertyName,
              object NewValue)
          {
              if (Target == null) return; //or throw exception
      
              System.Reflection.PropertyInfo prop = Target.GetType().GetProperty(PropertyName);
      
              if (prop == null) return; //or throw exception
      
              object value = prop.GetValue(Target, null);
      
              prop.SetValue(Target, NewValue, null);
          }
      }
      

      【讨论】:

        【解决方案7】:

        如果您使用的是 .Net 4,您现在可以使用 dynamic 关键字。

        dynamic foo = account;
        foo.Reference = "124ds4EE2s";
        

        【讨论】:

          【解决方案8】:

          我使用了 Richard 的反射方法,但详细说明了 set 方法来处理正在使用的其他类型,例如字符串和空值。

          public object this[string propertyName]
          {
              get
              {
                  PropertyInfo property = GetType().GetProperty(propertyName);
                  return property.GetValue(this, null);
              }
              set
              {
                  PropertyInfo property = GetType().GetProperty(propertyName);
                  Type propType = property.PropertyType;
                  if (value == null)
                  {
                      if (propType.IsValueType && Nullable.GetUnderlyingType(propType) == null)
                      {
                          throw new InvalidCastException();
                      }
                      else
                      {
                          property.SetValue(this, null, null);
                      }
                  }
                  else if (value.GetType() == propType)
                  {
                      property.SetValue(this, value, null);
                  }
                  else
                  {
                      TypeConverter typeConverter = TypeDescriptor.GetConverter(propType);
                      object propValue = typeConverter.ConvertFromString(value.ToString());
                      property.SetValue(this, propValue, null);
                  }
              }
          }
          

          如果转换不起作用,SetValue() 函数会抛出错误。

          【讨论】:

            【解决方案9】:

            使用反射体和表达式体

                    public dynamic this[string memberName]
                    {
                        get => GetType().GetProperty(memberName).GetValue(this, null);
                        set => GetType().GetProperty(memberName).SetValue(this,value, null);
                    }
            

            【讨论】:

              【解决方案10】:

              这是一个简单的例子,希望对你有帮助

              static void Main(string[] args)
              {
                  Operators op = new Operators()
                  {
                      ID = 1,
                      Name = "Edward",
                      email = "e.lorenz@mail.com",
                      Pass = "123456",
                      Auth1 = "EDF3242523@FFSDGDF"
                  };
              
                  var typei = op.GetType();
                  var ss = typei.GetProperties().Where(m => m.GetCustomAttributes<Password>().Count() > 0);
              
                  foreach (var item in ss)
                  {
                      var text = typei.GetProperty(item.Name).GetValue(op).ToString();
                      
                      typei.GetProperty(item.Name).SetValue(op, Encrypt(text));
                  }
              
                  Console.WriteLine(op.Pass);
                  Console.WriteLine(op.Auth1);
              
                  Console.ReadKey();
              }
              

              【讨论】:

                【解决方案11】:

                如何通过字符串名称使用反射访问对象中的列表
                公共列表 Table1 { 获取;放; } = 新列表();

                【讨论】:

                • 答案不是提出新问题的地方... - 请创建一个新问题。此外,您可能应该提供更多上下文或更完整的代码,以使其他人能够找到您问题的答案。
                • 如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-11-16
                • 1970-01-01
                • 1970-01-01
                • 2010-10-03
                • 1970-01-01
                • 2014-07-18
                • 2020-04-21
                相关资源
                最近更新 更多