Доступ к свойству объекта в виде строки и установка его значения
У меня есть экземпляр Account
учебный класс. Каждый объект учетной записи имеет владельца, ссылку и т. Д.
Один из способов получить доступ к свойствам учетных записей - через такие средства доступа, как
account.Reference;
но я хотел бы иметь возможность получить к нему доступ с помощью динамических селекторов строк, таких как:
account["PropertyName"];
так же, как в JavaScript. Так что я бы account["Reference"]
который будет возвращать значение, но я также хотел бы иметь возможность назначить новое значение после этого, как:
account["Reference"] = "124ds4EE2s";
Я заметил, что могу использовать
DataBinder.Eval(account,"Reference")
чтобы получить свойство на основе строки, но с помощью этого я не могу присвоить значение свойству.
Есть идеи, как я могу это сделать?
11 ответов
Прежде всего, вы должны избегать использования этого; 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");
Вы можете попробовать объединить индексатор с отражением...
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);
}
}
Я использовал метод отражения от Ричарда, но разработал метод 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() выдаст ошибку, если преобразование не работает.
Если вы используете.Net 4, вы можете использовать динамическое ключевое слово сейчас.
dynamic foo = account;
foo.Reference = "124ds4EE2s";
Если они являются вашими собственными объектами, вы можете предоставить индексатор для доступа к полям. Я не очень рекомендую это, но это позволило бы то, что вы хотите.
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
}
}
Обратите внимание, что при этом вы теряете безопасность типов.
Я согласен с предыдущими постерами, что вам, вероятно, нужно использовать свойства. Отражение очень медленное по сравнению с прямым доступом к собственности.
С другой стороны, если вам нужно вести список пользовательских свойств, вы не можете использовать свойства 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;
}
}
}
Я лично предпочитаю работать с методами расширения, поэтому вот мой код:
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);
}
}
Вам нужно использовать Reflection:
PropertyInfo property = typeof(Account).GetProperty("Reference");
property.SetValue(myAccount, "...", null);
Обратите внимание, что это будет очень медленно.
Используйте тела отражения и выражения
public dynamic this[string memberName]
{
get => GetType().GetProperty(memberName).GetValue(this, null);
set => GetType().GetProperty(memberName).SetValue(this,value, null);
}
как получить доступ к списку в объекте, используя отражение по имени строки
public List Table1 { get; установлен; } = новый список();
Вот простой пример, надеюсь, поможет
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();
}