Ответы:
Да, вы можете использовать Type.InvokeMember():
using System.Reflection;
MyObject obj = new MyObject();
obj.GetType().InvokeMember("Name",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, obj, "Value");
Это вызовет исключение, если objне было вызвано свойство Nameили его нельзя установить.
Другой подход состоит в том, чтобы получить метаданные для свойства, а затем установить его. Это позволит вам проверить наличие свойства и убедиться, что оно может быть установлено:
using System.Reflection;
MyObject obj = new MyObject();
PropertyInfo prop = obj.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance);
if(null != prop && prop.CanWrite)
{
prop.SetValue(obj, "Value", null);
}
obj.GetType().GetProperty("Name")?.GetSetMethod()?.Invoke(...)
CanWrite=Falseтипов, верно?
Вы также можете сделать:
Type type = target.GetType();
PropertyInfo prop = type.GetProperty("propertyName");
prop.SetValue (target, propertyValue, null);
где target - это объект, для которого будет установлено его свойство.
Отражение, в основном, т.е.
myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null);
или есть библиотеки, которые помогут как с точки зрения удобства, так и производительности; например с FastMember :
var wrapped = ObjectAccessor.Create(obj);
wrapped[property] = "Bob";
(что также имеет то преимущество, что не нужно заранее знать, является ли это поле по сравнению со свойством)
Или вы можете обернуть один вкладыш Марка в свой собственный класс расширения:
public static class PropertyExtension{
public static void SetPropertyValue(this object obj, string propName, object value)
{
obj.GetType().GetProperty(propName).SetValue(obj, value, null);
}
}
и назовите это так:
myObject.SetPropertyValue("myProperty", "myValue");
Для правильной оценки давайте добавим метод для получения значения свойства:
public static object GetPropertyValue(this object obj, string propName)
{
return obj.GetType().GetProperty(propName).GetValue (obj, null);
}
Используйте что-то вроде этого:
public static class PropertyExtension{
public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
{
PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
property.SetValue(p_object, Convert.ChangeType(value, property.PropertyType), null);
}
}
или
public static class PropertyExtension{
public static void SetPropertyValue(this object p_object, string p_propertyName, object value)
{
PropertyInfo property = p_object.GetType().GetProperty(p_propertyName);
Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
object safeValue = (value == null) ? null : Convert.ChangeType(value, t);
property.SetValue(p_object, safeValue, null);
}
}
Вы также можете получить доступ к полям, используя аналогичную манеру:
var obj=new MyObject();
FieldInfo fi = obj.GetType().
GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance);
fi.SetValue(obj,value)
С отражением все может быть открытой книгой :) В моем примере мы привязываемся к частному полю уровня экземпляра.
Вы можете попробовать это, когда хотите массово назначить свойства объекта из другого объекта, используя имена свойств:
public static void Assign(this object destination, object source)
{
if (destination is IEnumerable && source is IEnumerable)
{
var dest_enumerator = (destination as IEnumerable).GetEnumerator();
var src_enumerator = (source as IEnumerable).GetEnumerator();
while (dest_enumerator.MoveNext() && src_enumerator.MoveNext())
dest_enumerator.Current.Assign(src_enumerator.Current);
}
else
{
var destProperties = destination.GetType().GetProperties();
foreach (var sourceProperty in source.GetType().GetProperties())
{
foreach (var destProperty in destProperties)
{
if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
{
destProperty.SetValue(destination, sourceProperty.GetValue(source, new object[] { }), new object[] { });
break;
}
}
}
}
Я только что опубликовал пакет Nuget, который позволяет настраивать не только свойства первого уровня, но и вложенные свойства в данном объекте любой глубины.
Вот посылка
Устанавливает значение свойства объекта по его пути от корня.
Объект может быть сложным объектом, а свойство может быть многоуровневым вложенным свойством или может быть свойством непосредственно под корнем. ObjectWriterнайдет свойство, используя параметр свойства path, и обновит его значение. Путь свойства - это добавленные имена свойств, посещаемых от корня до свойства конечного узла, которое мы хотим установить, ограниченного строковым параметром delimiter.
Использование:
Для настройки свойств непосредственно под корнем объекта:
То есть. LineItemкласс имеет свойство int, называемоеItemId
LineItem lineItem = new LineItem();
ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null);
Для настройки вложенных свойств на нескольких уровнях ниже корня объекта:
То есть. InviteУ класса есть свойство с именем State, которое имеет свойство Invite(типа приглашения), у которого есть свойство Recipientс именем Id.
Чтобы сделать вещи еще более сложными, Stateсвойство не является ссылочным типом, оно является struct.
Вот как вы можете установить свойство Id (в строковое значение «outlook») внизу дерева объектов в одной строке.
Invite invite = new Invite();
ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_");
Основываясь на предложении MarcGravell, я построил следующий статический метод. Метод обычно назначает все подходящие свойства от исходного объекта к цели, используя FastMember
public static void DynamicPropertySet(object source, object target)
{
//SOURCE
var src_accessor = TypeAccessor.Create(source.GetType());
if (src_accessor == null)
{
throw new ApplicationException("Could not create accessor!");
}
var src_members = src_accessor.GetMembers();
if (src_members == null)
{
throw new ApplicationException("Could not fetch members!");
}
var src_class_members = src_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
var src_class_propNames = src_class_members.Select(x => x.Name);
var src_propNames = src_members.Except(src_class_members).Select(x => x.Name);
//TARGET
var trg_accessor = TypeAccessor.Create(target.GetType());
if (trg_accessor == null)
{
throw new ApplicationException("Could not create accessor!");
}
var trg_members = trg_accessor.GetMembers();
if (trg_members == null)
{
throw new ApplicationException("Could not create accessor!");
}
var trg_class_members = trg_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive);
var trg_class_propNames = trg_class_members.Select(x => x.Name);
var trg_propNames = trg_members.Except(trg_class_members).Select(x => x.Name);
var class_propNames = trg_class_propNames.Intersect(src_class_propNames);
var propNames = trg_propNames.Intersect(src_propNames);
foreach (var propName in propNames)
{
trg_accessor[target, propName] = src_accessor[source, propName];
}
foreach (var member in class_propNames)
{
var src = src_accessor[source, member];
var trg = trg_accessor[target, member];
if (src != null && trg != null)
{
DynamicPropertySet(src, trg);
}
}
}
var val = Convert.ChangeType(propValue, propInfo.PropertyType);source: devx.com/vb2themax/Tip/19599