none
PropertyInfo.SetValue throws exception 'Cannot convert Type 'X' to type 'X' RRS feed

  • Question

  • Similar questions have been asked earlier, and I have gone through each of them, none of the answers solved my problem.

    Here is the case, I have class:

    namespace BusinessServices.Exposure.Data
    {
        [DataContract]
        public class RiskItemBO : ExposureBO
        {
            [DataMember]
            public RiskItemBusinessService RiskItemBusinessService { get; set; }
    
        }
    }

    I have it in a DLL, on which I am trying to use reflection to build an object of type "RiksItemBO" -- please note that I will not have access to source code while building object, only the DLL.

    I used following code to retrieve all the properties of DLL:

    //ClassName in case of example is RiskItemBO
    Type t = Assembly.LoadFile(dllPath).GetType(ClassName);
    PropertyInfo[] properties = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    foreach (PropertyInfo property in properties) {
        Object setObject = getInstance(dllPath, property.FullName); //Returns instance of the property object (instance of RiskItemBusinessService in case of this example)
        property.SetValue(obj, setObject); //EXCEPTION!!
    }

    I get exception as soon as I try to set the value. I have tried everything mentioned in similar posts but to no avail.

    Thursday, December 27, 2012 12:24 AM

Answers

  • "However, the path for LoadFile and references in the project is same."

    That's actually a problem, when you add a reference to a dll the reference path doesn't matter. The project system copies the to the executable directory because that's where the executable will look for it. The original reference path is not used or known at runtime.

    • Marked as answer by BabbuP Friday, December 28, 2012 12:44 AM
    Thursday, December 27, 2012 6:53 PM
    Moderator

All replies

  • Hi Babbup,

    Welcome to the MSDN Forum.

    I didn't reproduce this scenario, but you can try this code snippet:

                string Classname = "ClassLibraryForReflection.RiskItemBO";
                Assembly ass = Assembly.LoadFile(dllPath);
                //ClassName in case of example is RiskItemBO
                Type t = ass.GetType(Classname);
                ConstructorInfo ci = t.GetConstructor(new Type[] { });
                object obj = ci.Invoke(new object[] { });
                PropertyInfo[] properties = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                foreach (PropertyInfo property in properties)
                {
                    Type tp = ass.GetType(property.PropertyType.FullName);
                    ConstructorInfo cip = tp.GetConstructor(new Type[] { });
                    object objp = cip.Invoke(new object[] { });
    
                    //object setObject = getInstance(dllPath, property.Name); //Returns instance of the property object (instance of RiskItemBusinessService in case of this example)
    
                    property.SetValue(obj, objp, null); //EXCEPTION!!
                }

    It worked for me.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, December 27, 2012 9:19 AM
    Moderator
  • I tested your code, but wondered what the "obj" is in your code.

    Here's how I testeds your code and it worked.

    static void Main(string[] args)
    {
        string dllPath = @"C:\Temp\PropertySetSample.Core.dll";
        string className = "PropertySetSample.Core.RiskItemBO";
    
        Assembly assembly = Assembly.LoadFile(dllPath);
    
        Type t = assembly.GetType(className);
    
        PropertyInfo[] properties = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    
        //// get RiskItemBO instance
        object riskItemBo = Activator.CreateInstance(t);
    
        foreach (PropertyInfo property in properties)
        {
            //// get RiskItemBusinessService instance
            Object setObject = GetInstance(property.PropertyType);
    
            //// set the RiskItemBO RiskItemBusinessService property value
            property.SetValue(riskItemBo, setObject, null);
        }
    }
    
    static object GetInstance(Type propertyType)
    {
        return Activator.CreateInstance(propertyType);
    }

    Thursday, December 27, 2012 12:54 PM
  • MasaSam:

    'obj' is the object of 'RiskItemBO' class which I have created using the following:

    Type t = Assembly.LoadFile(dllFile).GetType(ClassName);
    Object obj = Activator.CreateInstance(t);

    Thursday, December 27, 2012 5:42 PM
  • Usually such errors are the result of having different versions of an assembly loaded or having an assembly loaded multiple times. Why are you using Assembly.LoadFile?
    Thursday, December 27, 2012 5:46 PM
    Moderator
  • I do not have multiple versions of assembly for sure, however, I may have multiple assemblies loaded (not sure about it though). I use Assembly.LoadFile to get the Type 't' which I am using in the next line to create instance of the class provided by the user. A few things to note:

    1. getInstance is a recursive function, so, for example, in the example I provided getInstance() not only creates object of type RiskItemBO, but also RiskItemBusinessService, then after it has created object of RiskItemBusinessService and come down the stack, it is trying to set the variable of RiskItemBusinessService to the object it just created. I am getting exception at that time.
    2. I have also referenced all the assemblies which I think I will be using (for creating their objects) in my project itself. I have done it because I was getting FileNotFoundException.

    Is there any other way to create the instance of the class, get all its properties without loading the assembly? I am ready to try that method.

    Thursday, December 27, 2012 6:06 PM
  • "I have also referenced all the assemblies"

    Hmm, are you loading the assembly with LoadFile from the same directory as the executable? If you're loading from somewhere else then the assemblies are considered different and as a result types are different too.

    Since you have added reference to those assemblie you may as well do something like

    typeof(SomeTypeInThatAssembly).Assembly

    instead of Assembly.LoadFile.

    Or you can use Assembly.Load and specify only the name of the assembly, not the path.

    Thursday, December 27, 2012 6:39 PM
    Moderator
  • Well, the executable is in a different directory. However, the path for LoadFile and references in the project is same. I will try the method you just mentioned and get back to you. Thanks!
    Thursday, December 27, 2012 6:44 PM
  • "However, the path for LoadFile and references in the project is same."

    That's actually a problem, when you add a reference to a dll the reference path doesn't matter. The project system copies the to the executable directory because that's where the executable will look for it. The original reference path is not used or known at runtime.

    • Marked as answer by BabbuP Friday, December 28, 2012 12:44 AM
    Thursday, December 27, 2012 6:53 PM
    Moderator
  • Hi Mike,

    I can't believe I am asking this question, but where exactly should I copy the DLLs in the project directory? Is it under /bin or /bin/Debug or /bin/Release or somewhere else. I ask this because I am getting FileNotFoundException when I changed the reference after I had copied the files to /bin/Debug

    EDIT:

    For future reference, I copied all the DLL into the ConsoleApplication1 which is the main application calling my class library, and referenced the class library to the ConsoleApplication1's DLL.

    • Edited by BabbuP Friday, December 28, 2012 12:46 AM
    Thursday, December 27, 2012 10:46 PM
  • "but where exactly should I copy the DLLs in the project directory?"

    Where the executable is, tipically bin\Debug or bin\Release.

    "I ask this because I am getting FileNotFoundException when I changed the reference after I had copied the files to /bin/Debug"

    There's no need to change existing references, just make sure that when you use LoadFile you specify a path to a dll in the executable dir, not a path to a referenced dll.

    Friday, December 28, 2012 7:04 AM
    Moderator