0

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.

  • 3
    `Currency` and `Price` aren't properties on the passed-in object. You get those from the object referenced by the `BasePrice` variable. –  Apr 12 '21 at 18:14
  • You're saying that they are poperties of BasePrice? If so how can I get all porperties and sub-properties how should I change my cycle? @Amy – Filipe Bispo Apr 12 '21 at 18:21
  • 2
    IMO, I don't think reflection should be used. I don't see what its gaining you, here. –  Apr 12 '21 at 18:24
  • I want to do a method that receives an object and can iterate through all properties (subProperties) and match them with a list so if a converstion needs to be done it will authomatically change it's a value. So I can call it passing the object as reference, instead of having to go through all the objects and manually transform the data. If you have a better suggestion It's appreciated – Filipe Bispo Apr 12 '21 at 18:31

2 Answers2

0

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 = ...
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Would there be a way to maintain the the loop, and understand that BasePrice is a complex type and call the function passing it that object? Do I need to use typeof(RatePlanBasePrice) or is there a generic way to do it? Or it can't be done? – Filipe Bispo Apr 12 '21 at 18:43
  • You're right, using linq you can query I'll try use your code to see if I can achieve what I want. Thanks. – Filipe Bispo Apr 12 '21 at 19:16
0

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);
        }
    }
    
}
Joshua Robinson
  • 3,399
  • 7
  • 22