Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cast an object originated from Type A to Type B in .NET?

I have created a project which contains two projects. one is console application and the ohter is class library project.

I added the dll reference from class library project to the console application.

Now when I return an object from class library project, it can be retrieved in console application but if I try to cast it, it's not working.

It throws the error as cannot convert type a to type b.

I am struggling with this error for many hours.

My Code for Class Library Project:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassLibrary1
{
    public class Class1
    {
        public object dyn()
        {
            var obj = new { ID = 2, Name = "Rajesh" };
            return obj;
        }
    }
}

On the above I returned a list as object.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq;
using System.Data.SqlClient;
using System.Collections;
using System.Data;
using ClassLibrary1;
using System.Reflection;
using System.ComponentModel;
namespace ConsoleApplication2
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Program objPgm = new Program();
            Class1 objCls=new Class1();            
            object obj = objCls.dyn();
            var list = objPgm.cast(obj, new { ID = 0, Name = "" });
        }

        public  T cast<T>(object obj,T type) 
        {          
            return (T)obj; 
        }
}

On above code I retrieved the object from Class Library project and on trying to cast InvalidCastException is thrown.

Is there any fix for this.

Please help me on this issue.

Thanks in advance.

like image 878
RajeshKannan Avatar asked Jan 12 '23 22:01

RajeshKannan


2 Answers

It appears you're using CastByExample trick. It won't work out of the assembly since compiler generates two independent anonymous types in each assembly.

Best work around is to use your own type. and share it in common assembly

public class MyData
{
   public int ID {get;set;}
   public string Name{get;set;}
}
like image 79
Sriram Sakthivel Avatar answered Jan 22 '23 12:01

Sriram Sakthivel


Anonymous types only share the same compile-time type if:

  • they share the exact same parameter names, types, and order
  • they exist in the same assembly

Or from the MSDN:

If two or more anonymous object initializers in an assembly specify a sequence of properties that are in the same order and that have the same names and types, the compiler treats the objects as instances of the same type.

The first you have, but the second you do not. So, even though the two anonymous types look identical, as far as C# and the runtime are concerned, they are two completely different, incompatible types.

Ideally, anonymous types should not be passed back out of methods as they are (as you are finding now) not exactly useable.

In this case, you are far better off simply defining a class in your ClassLibrary1 to contain the ID and Name. Doing so strongly types the whole process and eliminates the need to essentially duplicate the structure of the information you're returning.


To give you an example of what you're code is (more or less) doing now:

namespace ClassLibrary1
{
    internal class ClassLibrary1_AnonObj1
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

    public class Class1
    {
        public object dyn()
        {
            var obj = new ClassLibrary1_AnonObj1 { ID = 2, Name = "Rajesh" };
            return obj;
        }
    }
}

namespace ConsoleApplication2
{
    internal class ClassLibrary2_AnonObj2
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Program objPgm = new Program();
            Class1 objCls=new Class1();            
            object obj = objCls.dyn();
            var list = objPgm.cast(obj, new ClassLibrary2_AnonObj2 { ID = 0, Name = "" });
        }

        public  T cast<T>(object obj,T type) 
        {          
            return (T)obj; 
        }
    }
}

Which would be like casting:

ClassLibrary1_AnonObj1 obj = new ClassLibrary1_AnonObj1();
ClassLibrary2_AnonObj2 obj2 = (ClassLibrary2_AnonObj2)obj;

This is why it would fail, as the two types appear completely different. If instead you declare and use your own class:

namespace ClassLibrary1
{
    public class MyInfo
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

    public class Class1
    {
        public MyInfo dyn()
        {
            var obj = new MyInfo { ID = 2, Name = "Rajesh" };
            return obj;
        }
    }
}

namespace ConsoleApplication2
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Program objPgm = new Program();
            Class1 objCls=new Class1();            
            MyInfo obj = objCls.dyn();
        }
    }
}

Which eliminates any need for casting. Or if you need it to keep it returning object, you can simply cast it at this point:

Class1 objCls=new Class1();            
MyInfo obj = (MyInfo)objCls.dyn();

Though I suspect your use of dyn() implies that you intend to have some dynamically created content, or different types returned. Perhaps more context, refactoring, or a better design is warranted.

like image 32
Chris Sinclair Avatar answered Jan 22 '23 14:01

Chris Sinclair