1

Today working on my code I came across a phase where i needed to cast an object type to my custom class which should have been very simple, but I ended up hours resolving System.InvalidCastException, finally I ended up using JsonConvert to get the job done.

I am not really sure if there was a better way to handle this, if there is I would like to know what I could have done better.

Given is the structure of my custom class

using SQLite.Net.Attributes;
namespace DataContract
{
public class Event
{
    #region Properties
    [PrimaryKey]
    public int Id { get; set; }

    public string Name { get; set; }

    public DateTime EventDateTime { get; set; }

    #endregion
}
}

The Event class is inside a DataContract shared project and my folder structure of the project is given below,

Solution structure

Using EntityFramework I am getting a List<Event> from my sqlite database and I am using this list to display elements in my tableview for android, I go through one item at a time in my list and try to cast it to my custom Event class.

Given is the code for the same which i tried

//tableItems is my IList<object>
var item = tableItems[position];

        var view = convertView;
        if (view == null)
        {
            view = context.LayoutInflater.Inflate(Resource.Layout.NativeAndroidEventCell, null);
        }


        if (item.GetType().FullName.Equals("DataContract.Event"))
        {
                  var x = item as DataContract.Event; // returns null
                  var y = (DataContract.Event)item; // cast exception
                var z = item.GetType().GetField("Name"); // returns null    

        }

The exception I get is given in the image, I am unable to see the stacktrace here as it shows null

enter image description here

When I watch the value of item variable in the console I see that it shows me the exact values of what is being returned from the database and it even shows me the correct type in the type column but for some reason when i step through the code the value of x is null.

enter image description here

As my last resort I ended up using JsonConvert class and did something like this

if (item.GetType().FullName.Equals("DataContract.Event"))
        {
           //Not sure if this is the right approach here but it works
            var serializedObject = JsonConvert.SerializeObject(item, Formatting.Indented);
            var deserializedObject = JsonConvert.DeserializeObject<DataContract.Event>(x);

            view.FindViewById<TextView>(Resource.Id.textView1).Text = deserializedObject.Name;
            view.FindViewById<TextView>(Resource.Id.textView2).Text = deserializedObject.EventDateTime.ToString();
        }

The JsonConvert works and I am able to resolve my issue, but what I am more looking at is to know if I could have done better to resolve this than using JsonConvert Or what I did was correct. Please suggest

Bug Hunter Zoro
  • 1,743
  • 18
  • 21
  • Isn't `item` already of type `DataContract.Event`? – James T Apr 30 '18 at 00:59
  • 1
    It sounds like you've might have defined Event in more than one assembly or even possibly from the same assembly loaded in different contexts. How exactly was tableItems populated? – Mike Zboray Apr 30 '18 at 01:11
  • What @mikez said, what are the exact full qualified names its complaining about – TheGeneral Apr 30 '18 at 01:23
  • @JamesT no it's not, as mentioned in the code it takes its value from the tableItems which is of type List – Bug Hunter Zoro Apr 30 '18 at 03:26
  • @mikez updated my question with my folder structure, do you think that is the issue? Also tableItems is a IList wanted to keep it generic as the same view will be used in multiple places and it gets the data from the UI layer which can be List – Bug Hunter Zoro Apr 30 '18 at 03:56
  • @NSDumb Ah it's in a ["shared project"](https://stackoverflow.com/q/30634753/517852)? So the way shared projects work is that the code is compiled into referring projects, so there is a version in your db project and a version in your droid project? Are you getting any warnings about this type being in multiple assemblies or being ambiguous? My point with how tableItems is populated is to get at how EF is loading it because obviously its finding some type called "DataContract.Event" but not the one you think you are using. – Mike Zboray Apr 30 '18 at 04:08
  • @NSDumb Do you get the same result if you declare `item` as `object` explicitly, instead of using `var`? – James T Apr 30 '18 at 04:55
  • @JamesT yes the results are same, i tried that before posting the question, it's just that i want to know if using JsonConvert class was the right trade off here, because casting should not be that tuff, what confuses me that my console shows that item is of type DataContract.Event but then too when i try to cast it, throws an exception, i will try changing the name of Event class to something else and see if that works avoiding the JsonConvert will keep you posted – Bug Hunter Zoro Apr 30 '18 at 12:02

2 Answers2

0

Actually after reading this several times and some guess work, here is your problem.

The Event class you declare below e.g

List<Event> tableItems ...

is "not" pointing to the exactly the same class as when you are trying to cast here

(DataContract.Event)item;

This maybe confirmed by right clicking both types and selecting go to definition, they are probably different places.

Most likely cause

  1. One is a generated proxy (if this is coming from WCF, or over the wire), one is the concrete class
  2. Another likely cause, you have different versions of the same assembly in which they live. Check your references

Also try and break point the code, and determine if these types are indeed pointing to the same place. This is the problem and you need to somehow rectify it.

Also note : if you are dealing with proxies and concrete classes you cant cast them (even if they are exactly the same) you will have to copy the properties across manually or use something like automapper or like you are doing serialize and deserialize

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • Thanks for the quick response, I did check that and tableItems are of type IList which gets the data from the UI layer and then I cast them at runtime based on the contents present inside them for specific pages of my applications, like page A returns List and page B returns List does that makes sense – Bug Hunter Zoro Apr 30 '18 at 04:00
0

After long hours of research, I ended up using my own JSONSerialization approach to handle the casting as mentioned in the question

var serializedObject = JsonConvert.SerializeObject(item, Formatting.Indented);
            var deserializedObject = JsonConvert.DeserializeObject<DataContract.Event>(x);

            view.FindViewById<TextView>(Resource.Id.textView1).Text = deserializedObject.Name;
            view.FindViewById<TextView>(Resource.Id.textView2).Text = deserializedObject.EventDateTime.ToString();
Bug Hunter Zoro
  • 1,743
  • 18
  • 21