Respostas:
Sim, você pode usar Type.InvokeMember():
using System.Reflection;
MyObject obj = new MyObject();
obj.GetType().InvokeMember("Name",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, obj, "Value");
Isso gerará uma exceção se objnão tiver uma propriedade chamada Nameou se não puder ser definida.
Outra abordagem é obter os metadados da propriedade e configurá-los. Isso permitirá que você verifique a existência da propriedade e verifique se ela pode ser configurada:
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=Falsetipos, certo?
Você também pode fazer:
Type type = target.GetType();
PropertyInfo prop = type.GetProperty("propertyName");
prop.SetValue (target, propertyValue, null);
onde target é o objeto que terá sua propriedade definida.
Reflexão, basicamente, ie
myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null);
ou existem bibliotecas para ajudar em termos de conveniência e desempenho; por exemplo, com FastMember :
var wrapped = ObjectAccessor.Create(obj);
wrapped[property] = "Bob";
(que também tem a vantagem de não precisar saber com antecedência se é um campo versus uma propriedade)
Ou você pode envolver um liner de Marc dentro de sua própria classe de extensão:
public static class PropertyExtension{
public static void SetPropertyValue(this object obj, string propName, object value)
{
obj.GetType().GetProperty(propName).SetValue(obj, value, null);
}
}
e chame assim:
myObject.SetPropertyValue("myProperty", "myValue");
Para uma boa medida, vamos adicionar um método para obter um valor de propriedade:
public static object GetPropertyValue(this object obj, string propName)
{
return obj.GetType().GetProperty(propName).GetValue (obj, null);
}
Use algo assim:
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);
}
}
ou
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);
}
}
Você também pode acessar os campos usando uma maneira semelhante:
var obj=new MyObject();
FieldInfo fi = obj.GetType().
GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance);
fi.SetValue(obj,value)
Com reflexão, tudo pode ser um livro aberto :) No meu exemplo, estamos vinculando a um campo no nível da instância privada.
Você pode tentar isso quando quiser atribuir em massa propriedades de um Objeto de outro Objeto usando nomes de Propriedades:
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;
}
}
}
}
Acabei de publicar um pacote Nuget que permite configurar não apenas as propriedades de primeiro nível, mas também as propriedades aninhadas no objeto especificado em qualquer profundidade.
Aqui está o pacote
Define o valor de uma propriedade de um objeto pelo caminho a partir da raiz.
O objeto pode ser um objeto complexo e a propriedade pode ser uma propriedade aninhada profunda em vários níveis ou pode ser uma propriedade diretamente sob a raiz. ObjectWriterencontrará a propriedade usando o parâmetro path da propriedade e atualizará seu valor. Caminho da propriedade são os nomes anexados das propriedades visitadas da raiz até a propriedade do nó final que queremos definir, delimitadas pelo parâmetro delimiter string.
Uso:
Para configurar as propriedades diretamente sob a raiz do objeto:
Ou seja. LineItemclasse tem uma propriedade int chamadaItemId
LineItem lineItem = new LineItem();
ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null);
Para configurar a propriedade aninhada vários níveis abaixo da raiz do objeto:
Ou seja. InviteA classe possui uma propriedade chamada State, que possui uma propriedade chamada Invite(do tipo Invite), que possui uma propriedade chamada Recipient, que possui uma propriedade chamada Id.
Para tornar as coisas ainda mais complexas, a Statepropriedade não é um tipo de referência, é a struct.
Aqui está como você pode definir a propriedade Id (para o valor da string "outlook") na parte inferior da árvore de objetos em uma única linha.
Invite invite = new Invite();
ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_");
Com base na sugestão de MarcGravell, construí o método estático a seguir. O método atribui genericamente todas as propriedades correspondentes do objeto de origem ao destino usando o 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);fonte: devx.com/vb2themax/Tip/19599