C# Not getting all properties from GetProperties

527 views Asked by At

I'm going around in cricles changing and rechanging not understanding why I'm not getting the values I want to, maybe someone can shed some light on it.

I have this object

var result = new GetRatePlanListResponse
        {
            RatePlanId = prodRpsResult.Id,
            RatePlanName = prodRpsResult.Name,
            EffectiveStartDate = prodRpsResult.EffectiveStartDate,
            EffectiveEndDate = prodRpsResult.EffectiveEndDate,
            BillingPeriod = prodRpsResult.PRDP_BillingFrequency__c.HasValue ? prodRpsResult.PRDP_BillingFrequency__c.Value.ToString() : null,
            ShippingSchedule = prodRpsResult.PRDP_DeliveryFrequency__c.HasValue ? prodRpsResult.PRDP_DeliveryFrequency__c.Value.ToString() : null,
            UsageLevel = prodRpsResult?.PRDP_UsageLevel__c,
            IncludedUnits = prodRpsResult?.PRDP_NumberofPackages__c,
            BasePrice = new RatePlanBasePrice
            {
                Currency = pricing != null ? pricing.Currency : string.Empty,
                Price = pricing != null && pricing.Price != null ? pricing.Price.Value : 0
            }
        };

Then I call this fucntion with that object has argument:

    public void PriceConverter<T>(ref T obj)
    {
        Type t = obj.GetType();

        foreach (var prop in t.GetProperties())
        {
            if (Enum.GetNames(typeof(RootPrices)).Any(x => x.ToLower() == prop.Name.ToLower()))
            {
                prop.SetValue(obj, ((int)(double.Parse((string)prop.GetValue(obj)) * 100)).ToString(), null);
            }
            
        }

    }

My problem is that for some reason I can't access the values Currency and Price. how can I do that?

EDIT:

Ok, guys thanks for the info,, I decided to change my approach since I can't get a way to change a generic object property if they have other objects inside since they respresent a different reference. Although I'm changing it I would appreciate if someone know a way to recursivly or iteratively change a referenced object and all the object it references and can provide a solution it would help me out in the future when I'm given a task to transform multiple objects data of pre-existing code base which have similar fields.

2

There are 2 answers

0
Joshua Robinson On

You could just call PriceConverter<T> recursively on the value of each property in t. You will need to implement some sort of filtering if you don't want to call PriceConverter<T> on properties of a specific type.

For the simple example you've given, you might be able to get away with only getting readable, mutable properties. Also, it doesn't look like the ref keyword is necessary since you're potentially mutating properties of obj, but not actually changing the reference.

void PriceConverter<T>(T obj)
{
    Type t = obj.GetType();
    foreach (var prop in t.GetProperties().Where(p => p.CanRead && p.CanWrite))
    {
        object value = prop.GetValue(obj);
        if (value != null)
        {
            PriceConverter(value);
        }

        if (Enum.GetNames(typeof(RootPrice)).Any(x => x.ToLower() == prop.Name.ToLower()))
        {
            prop.SetValue(obj, ((int)(double.Parse((string)prop.GetValue(obj)) * 100)).ToString(), null);
        }
    }
    
}
2
Dmitry Bychenko On

Both Currency and Price belongs to RatePlanBasePrice type not to GetRatePlanListResponse. So, you have to obtain BasePrice property first. If RatePlanBasePrice is a class (not struct):

  using System.Linq;
  using System.Reflection;

  ...  

  var prop = obj
    .GetType()
    .GetProperties()
    .FirstOrDefault(p => 
      string.Equals("BasePrice", p.PropertyType) &&
      p.CanRead &&
      typeof(RatePlanBasePrice).IsAssignableFrom(p.PropertyType));

  if (prop != null) {
    obj val = prop.GetValue(obj);

    if (val != null) {
      RatePlanBasePrice value = (RatePlanBasePrice) val;

      // Put relevant code here 
      val.Currency = ...
      val.Price = ...
    }
  }

If If RatePlanBasePrice is a struct:

  var prop = obj
    .GetType()
    .GetProperties()
    .FirstOrDefault(p => 
      string.Equals("BasePrice", p.PropertyType) &&
      p.CanRead && 
      p.CanWrite &&
      typeof(RatePlanBasePrice).IsAssignableFrom(p.PropertyType));

  if (prop != null) {
    // uncomment, if you need an old value  
    //var oldValue = (RatePlanBasePrice) (prop.GetValue(obj));

    prop.SetValue(obj, new RatePlanBasePrice() {
      // Put relevant code here
      Currency = ...
      Price = ... 
    });
  }

Edit: Yes, you can loop over properties, but why? If you use Linq, it's quite natural to put a single query. If you are looking for some kind of generic case, let's extract a method:

private static bool TryReadProperty<T>(object source, string name, out T value) {
  value = default(T);

  if (null == source)
    return false;

  var prop = source
    .GetType()
    .GetProperties()
    .FirstOrDefault(p => string.Equals(p.Name, name) &&
                         p.CanRead &&
                         typeof(T).IsAssignableFrom(p.PropertyType));

  if (null == prop)
    return false;

  value = (T) (prop.GetValue(prop.GetGetMethod().IsStatic ? null : source));

  return true;
}

then you can use it

if (TryGetProperty<RatePlanBasePrice>(obj, "BasePrice", out var value)) {
  // Put relevant code here 
  val.Currency = ...
  val.Price = ...
}