Jeff
Jeff

Reputation: 621

Using GetAttributeValue<T> Dynamically in CRM Online

I have C# code running to compare pre and post-images in CRM to determine if a field changed (long story short: external process I can't control is updating every field on a record every time, even if fields haven't changed). I want to use the CRM GetAttributeValue(attributeName) to do it, but I want to do it dynamically when I may not know the field name. So, for example, I want to do this:

// pretend the value of firstname is not hard-coded but submitted on a form    
// (not really on a form, but just know it's not hard-coded like it is below.)
string fieldToCheck = "firstname"; 
if (preImage.GetAttributeValue<T>(fieldToCheck) != postImage.GetAttributeValue<T>(fieldToCheck))
{
  // do something here. I've tried something like the below, but it doesn't work with error "t is a variable but used like a type". 
  Type t = preImage.Attributes[fieldToCheck].GetType();
  var val = preImage.GetAttributeValue<t>(fieldToCheck);

}

The problem I'm having is that <T> could be different depending on the value of fieldToCheck. In the case of firstname it would be <string>, in the case of new_DateOpened it would be <DateTime>, etc. I must be having a brain spasm because I should be able to figure out how to dynamically get the value of T, but can't.

Upvotes: 3

Views: 1807

Answers (2)

Henk van Boeijen
Henk van Boeijen

Reputation: 7938

For most (if not all) attribute types you can rely on the common Equals(object o) method. This also works for the attributes based on classes EntityReference, OptionSetValue and Money.

You only need to do an extra check on null values. (When an attribute has a null value in the system it will not be present in the attribute collection of a pre- or post-image.)

public static bool IsAttributeModified(string attributeName, Entity preImage, Entity postImage)
{
    object preValue;

    if (preImage.Attributes.TryGetValue(attributeName, out preValue))
    {
        object postValue;
        return !postImage.Attributes.TryGetValue(attributeName, out postValue) || !preValue.Equals(postValue);
    }

    return postImage.Attributes.ContainsKey(attributeName);
}

Upvotes: 1

trousyt
trousyt

Reputation: 356

A generic type parameter T is not equal to an instance of type Type. You can go from type param T -> Type using typeof(T), but not from Type -> T easily. Type T must be known at compile time normally.

You CAN apparently do this with reflection per here (How do I use reflection to call a generic method?):

MethodInfo method = typeof(Entity).GetMethod("GetAttributeValue");
MethodInfo generic = method.MakeGenericMethod(t);
generic.Invoke(preImage, fieldToCheck); // and postImage

Upvotes: 1

Related Questions