jeudi 9 juillet 2020

Casting to object by GetType?

Simplification :

We have our own DB mapper from SqlDataReader to Entity.

In normal circumstances, this is the case :

void Main()
{
    object s = (int?)1;
    MyClass newObjectToReturn = Activator.CreateInstance<MyClass>();
    typeof(MyClass).InvokeMember("MyProperty", BindingFlags.SetProperty, null, newObjectToReturn, new Object[] { s });



}
class MyClass
{
    public int? MyProperty { get; set; }
}

One thing to mention is that this line :

object s = (int?)1;

Is here to simulate the SqlDataReader which wraps the value as Object. In debug, I see it as Object{int}

All Ok and works.

So where is the problem?

The problem is that the type in DB is smallint , which is a Short in C# , and the type in the entity is an int?

So basically what's happening is this :

object s = (short?)1;
int? MyProperty  = (int?)s;

Which yields to exception :

Method 'UserQuery+MyClass.MyProperty' not found.

   at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
   at System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args)
   at UserQuery.Main() in C:\Users\royin\AppData\Local\Temp\LINQPad5\_oexzmkdz\query_deibtt.cs:line 33
   at LINQPad.ExecutionModel.ClrQueryRunner.Run()
   at LINQPad.ExecutionModel.Server.RunQuery(QueryRunner runner)
   at LINQPad.ExecutionModel.Server.StartQuery(QueryRunner runner)
   at LINQPad.ExecutionModel.Server.<>c__DisplayClass153_0.<ExecuteClrQuery>b__0()
   at LINQPad.ExecutionModel.Server.SingleThreadExecuter.Work()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

I already know how to solve it :

It's by changing :

typeof(MyClass).InvokeMember("MyProperty", BindingFlags.SetProperty, null, newObjectToReturn, new Object[] { s });

to

typeof(MyClass).InvokeMember("MyProperty", BindingFlags.SetProperty, null, newObjectToReturn, new Object[] { (int?)(short?)s });

// btw , this also works : `(int?)(dynamic)s`

Question:

How can I cast s to the entity's property type ?

(int?)(short?)s

I already know how to get type from the property :

newObjectToReturn.GetType().GetProperties().Where(otr =>otr.Name== "MyProperty").First().PropertyType

but how can I cast s to this ^ ?





Aucun commentaire:

Enregistrer un commentaire