I have the following class:
class CrmToRealTypeConverter : IConverter
{
#region IConverter Members
public object Convert<T>(T obj)
{
return Convert(obj);
}
#endregion
private DateTime? Convert(CrmDateTime obj)
{
return obj.IsNull == false ? (DateTime?)obj.UserTime : null;
}
private int? Convert(CrmNumber obj)
{
return obj.IsNull == false ? (int?)obj.Value : null;
}
private decimal? Convert(CrmDecimal obj)
{
return obj.IsNull == false ? (decimal?)obj.Value : null;
}
private double? Convert(CrmDouble obj)
{
return obj.IsNull == false ? (double?)obj.Value : null;
}
private float? Convert(CrmFloat obj)
{
return obj.IsNull == false ? (float?)obj.Value : null;
}
private decimal? Convert(CrmMoney obj)
{
return obj.IsNull == false ? (decimal?)obj.Value : null;
}
private bool? Convert(CrmBoolean obj)
{
return obj.IsNull == false ? (bool?)obj.Value : null;
}
}
I am trying to specialize the Convert method with concreate types.
Currently it just loops recursively in Convert<T>()
until a stack overflow occurs.
Polymorphism doesn't work on arguments to a method call. An approach you can use it to check the type of obj, cast it to the specific type and then call the appropriate overload.
public object Convert(object obj)
{
if (obj is CrmDateTime)
return Convert((CrmDateTime)obj);
if (obj is CrmNumber)
return Convert((CrmNumber)obj);
// ...
}
Late-binding doesn't happen the way you think it does; the compiler binds the call to Convert(obj)
in thepublic object Convert<T>(T obj)
method to the same method (recursive call). The behaviour you appear to be expecting is that the CLR will dynamically choose the most appropriate overload to execute at run-time, but it doesn't work that way. Try something like this instead:
public object Convert<T>(T obj)
{
if (obj == null)
throw new ArgumentNullException("obj");
var cdt = obj as CrmDateTime;
if (cdt != null)
return Convert(cdt); // bound at compile-time to DateTime? Convert(CrmDateTime)
var cn = obj as CrmNumber;
if (cn != null)
return Convert(cn); // bound at compile-time to int? Convert(CrmNumber)
// ...
throw new NotSupportedException("Cannot convert " + obj.GetType());
}
If you prefer, you can use reflection here. Such a solution would look something like:
// Making the method generic doesn't really help
public object Convert(object obj)
{
if (obj == null)
throw new ArgumentNullException("obj");
// Target method is always a private, instance method
var bFlags = BindingFlags.Instance | BindingFlags.NonPublic;
// ..which takes a parameter of the obj's type.
var parameterTypes = new[] { obj.GetType() };
// Get a MethodInfo instance that represents the correct overload
var method = typeof(CrmToRealTypeConverter)
.GetMethod("Convert", bFlags, null, parameterTypes, null);
if (method == null)
throw new NotSupportedException("Cannot convert " + obj.GetType());
// Invoke the method with the forwarded argument
return method.Invoke(this, new object[] { obj });
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With