Reputation: 167
i am trying to copy properties to update the supplier in my code
Here is my supplier update method
public bool UpdateSupplier(PurchaseOrderHeader header, string newSupplier)
{
try
{
var oldSupplier = GetSupplierForPoHeader(header);
Reflection.CopyPropertyValues(oldSupplier, newSupplier);
Console.WriteLine($"{oldSupplier} : {newSupplier}");
_context.SaveChanges();
return true;
}
catch (Exception ex)
{
Logger.LogException(ex);
throw;
}
}
Here is my method for updating the values.
public static void CopyPropertyValues(object source, object destination)
{
try
{
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.Name == "Id")
continue;
destProperty.SetValue(destination, sourceProperty.GetValue(source, new object[] { }),
new object[] { });
break;
}
}
catch (Exception e)
{
Console.WriteLine(@"Inner Exception: "+e.InnerException?.Message);
Console.WriteLine(@"Message: "+e.Message);
}
}
Any ideas?
I checked other stack overflow questions and it seems none of them are fixing my issue, i am fairly new to reflection so i have no idea how to go about fixing this myself.
Upvotes: 2
Views: 8567
Reputation: 5920
This error means that your property doesn't have any set method. You have few ways of fixing this but I'll point out only 2 of them :
1- Implement set
method in your properties :
public <type> PropertyName
{
get;
set; /// <-- here
}
2- Use this property's backing field:
Every property has it's own backing field which differs from implementation method. If you implemented your property as : public <type> Name {get;set;}
then your backing field's name is <Name >k__BackingField
which you can change as you like. To retrieve backing field use this code :
meObject.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where(prop => prop.Name.EndsWith("__BackingField"));
This will return your backing field of autoproperty.
Making final conclusion to your problem. Do not use GetProperties()
as properties always have some backing field. Use GetFields()
instead because all that properties are doing is just modifying their backing field or returns ( almost ) constant value.
Upvotes: 2
Reputation: 64628
Check these:
PropertyInfo.CanSet
)BindingFlags
(or use they code bellow).DeclaringType
, because private members are not found on the derived class (but the property is because of a public getter) or use they code bellow.If you want to access private setters, you may find this useful:
var setterMethod = propertyInfo.GetSetMethod(true);
setterMethod.Invoke(instance, new [] { value });
Note that you also get Indexers as properties. They take an additional argument. You probably want to exclude them also (!propertyInfo.GetIndexParameters().Any()
).
Upvotes: 3
Reputation: 2317
The GetProperties()
method has an overload that takes BindingFlags to specify how the reflection search is conducted;
source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.Public) // ... & and other flags you need
Upvotes: 0