I recently had a requirement to verify whether a value has
updated by comparing with the present value and the earlier value. In the
context of Dynamics CRM, I needed to compare the value of an attribute in the
target entity with the value of the same attribute from the preimage entity in
a post update plugin on a custom entity.
I had to write a method which will compare the values of two
object types and return true or false. However, the caveat is that these values
are reference types (and I assumed they do not have any IComparer
implementation and are sealed) and so the comparisons for each type will be
different (need to use different properties). The obvious way was to write a
method for each type, which would be difficult to maintain as there needs to be
a method for each of the object types supported by the Dynamics CRM SDK. So I
used an alternate approach where I wrote a single method (with the help of C#
generics) that would cater to all the different object types.
Here goes the method:
private bool IsValueUpdated <T>(T presentValue, T oldValue, Func<T, T, bool> comparer) where T: class
{
if (presentValue == null)
{
// if the present value is null, it means it was not updated in the update plugin
return false;
}
if (oldValue == null)
{
// if the old value is null, it means the old value was not populated but there is a new value (applicable during creation)
return true;
}
return comparer(presentValue, oldValue);
}
The above comments might be Dynamics CRM specific (but the
idea is to help you understand the approach used and can be applicable to any
.NET scenario as well).
The method is mostly easy to understand. However, I would
like to point out the third parameter in the method the “comparer” Func. Funcs
are a feature of C# that help us to encapsulate methods (a delegate type). We
can pass our custom comparer method in the Func using a lambda expression as
follows:
var isTypeUpdated = this.IsValueUpdated(typePresentValue, typeOldValue,
(presentValue, oldValue) => presentValue.Value != oldValue.Value);
var isCompanyUpdated = this.IsValueUpdated(companyPresentValue, companyOldValue,
(presentValue, oldValue) => presentValue.Id != oldValue.Id);
(presentValue, oldValue) => presentValue.Value != oldValue.Value);
var isCompanyUpdated = this.IsValueUpdated(companyPresentValue, companyOldValue,
(presentValue, oldValue) => presentValue.Id != oldValue.Id);
The highlighted portion shows 2 different method invocations
where we are passing the lambda expression for the comparer. If you note
carefully, the types are automatically inferred by the C# compiler, so we do
not need to explicitly state that the first invocation of the generic method is
for the OptionsetValue type, while the second is for the EntityReference type
(Dynamics CRM object types of interest for my case).
We can also create Func variables and store the lambda
expressions as local variables which we can pass in case we require another
method which has the same comparer implementation or we do not want to pass the
lambdas during the method invocation.
Please let me know your views on the above approach and you
are most welcome to share your ideas as well. Thanks in advance and have a
great time with C#/Dynamics CRM!
No comments:
Post a Comment