Corey James Carney
Corey James Carney

Reputation: 167

Property Set Method not found, Exception System.ArgumentException

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

Answers (3)

mrogal.ski
mrogal.ski

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.

Online example

Upvotes: 2

Stefan Steinegger
Stefan Steinegger

Reputation: 64628

Check these:

  • The property you try to set need to have a setter. (PropertyInfo.CanSet)
  • is the setter private, you have to tell the SetValue method, that it should set it anyway using the BindingFlags (or use they code bellow).
  • Is the property derived and the setter private, and you still want to set it, you need to get the property from the 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

Fredrik
Fredrik

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

Related Questions