Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type casting fails even though I have implicit operators

Tags:

c#

.net

casting

I have written custom type with implicit cast operator

public class TcBool : TcDataTypeBase
{
    public TcBool() : base(1, false) { } //For somewhat reason without this callin new TcBool() fails
    public TcBool(bool value = false) : base(1, value) { }

    public static implicit operator bool(TcBool var) => (bool)var.Value;

    public static implicit operator TcBool(bool value) => new TcBool(value);
}

public abstract class TcDataTypeBase
{
    public readonly byte Size;
    public readonly object Value;

    public string Name { get; set; }
    public int IndexGroup { get; set; }
    public int IndexOffset { get; set; }

    internal TcDataTypeBase(byte size, object value)
    {
        Size = size;
        Value = value;
    }

    internal TcDataTypeBase(string name, byte size, object value) : this(size, value)
    {
        Name = name;
    }
}

Then when I try to write it into a boolean property of an object using PropertyInfo.SetValue() it throws an exception saying it can't cast TcBool to System.Boolean.

Is there something preventing the reflection mechanisms from using the implicit conversion or am I missing something?

like image 729
Nidrax Avatar asked Mar 07 '23 14:03

Nidrax


2 Answers

The compiler doesn't know it has to cast anything, because SetValue accepts an object, which is type-compatible with TcBool without any cast (and indeed, you cannot define an implicit cast operator to an ancestor type). To force a cast, you can do this:

property.SetValue(instance, (bool)TcBool);

This will trigger your implicit cast operator and create a Boolean, which is then boxed into an object and passed to SetValue.

like image 79
John Wu Avatar answered Mar 15 '23 01:03

John Wu


Disclaimer: I realize that this is possibly overkill and will not work in case you don't know the types at compile time.


The important thing to know is that the implicit conversion operators are compiled into methods called "op_Implicit" and will therefore not automatically be called.

So I created this (rather long) and hacky helper method which converts an object of type TObject to an object of type TTo while taking into account implicit conversion operators:

public static object Convert<TObject, TTo>(TObject obj)
{
    IEnumerable<MethodInfo> implicitConversionOperators = obj.GetType()
                                                             .GetMethods()
                                                             .Where(mi => mi.Name == "op_Implicit");
    MethodInfo fittingImplicitConversionOperator = null;

    foreach (MethodInfo methodInfo in implicitConversionOperators)
    {
        if (methodInfo.GetParameters().Any(parameter => parameter.ParameterType == typeof(TObject)))
        {
            fittingImplicitConversionOperator = methodInfo;
        }
    }

    if (fittingImplicitConversionOperator != null)
    {
        return fittingImplicitConversionOperator.Invoke(null, new object[] {obj});
    }

    return (TTo) System.Convert.ChangeType(obj, typeof(TTo));
}

Of course it is far from being perfect, but it can be used like this

propertyInfo.SetValue(this, Helper.Convert<TcBool, bool>(new TcBool(true)));

to set the property. Of course, if you don't know the types at compile time / don't want to have to be that verbose you could try dynamic etc. as it is shown in the other answers.

like image 36
Thomas Flinkow Avatar answered Mar 15 '23 03:03

Thomas Flinkow