简体   繁体   中英

Casting object to generic T

I'm having a little trouble with some casts that i cant figure out out to solve.

I have this interface and the following implementations:

public interface IConfigureServiceOnServer
{
    void Configure(Service service);
}

public sealed class ServiceConfigurator : IConfigureServiceOnServer
{
 ...
}

I'm loading these types at runtime using a dictionary (that holds the assembly and type names) with the following method:

 public static T Resolve<T>(string type, params object[] values) where T : class
        {
            var split = refs[type].Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
            var assembly = Assembly.LoadFrom(split[0] + ".dll");
            var instance = assembly.CreateInstance(
                split[1], // the name of the Type to instantiate
                true,
                BindingFlags.CreateInstance,
                null,
                values, // the params to use in the constructor
                null,
                null);
            T ret = (T)instance; //also tried with 'instance as T'
            return ret;
        }

I get an invalid cast exception when calling it like this

Resolver.Resolve<IConfigureServiceOnServer>("serviceconfiguration", "");

I can't quite figure out why i get this exception because the same code works for the next interface and its implementation:

public interface IServiceManager
{
    void Create();
    void Configure();
}

public sealed class Service : IServiceManager
{
...
}

Any ideas why the same code works for the 2nd example and not for the first?

Thanks in advance.

EDIT:

When i'm debugging and i stop execution right before the return in the Resolve method i can use the immediate window - i test the cast and it works.

EDIT2: This is the exception message:

Unable to cast object of type 'Codegarten.Controller.Configuration.Service.ServiceConfigurator' to type 'Codegarten.Controller.Configuration.IConfigureServiceOnServer '.

EDIT3: Some more info - Someone suggested the type loaded using reflection could be wrong so i did a little more debugging. I checked to see if the loaded type implemented the desired interface using the immediate window in visual studio:

>instance.GetType().GetInterfaces()
{System.Type[1]}
    [0]: {Name = "IConfigureServiceOnServer" FullName = "Codegarten.Controller.Configuration.IConfigureServiceOnServer"}

SOLUTION
Ok, the problem was caused by the Assembly.LoadFrom method, which loaded the assembly into a different context than the applications.

I solved this issue by using Assembly.Load instead.

Are you absolutely sure that the type IConfigureServiceOnServer in the line

Resolver.Resolve<IConfigureServiceOnServer>("serviceconfiguration", "");

compiles to exactly the same type in the same namespace in the same assembly as the one in your class definition?

public sealed class ServiceConfigurator : IConfigureServiceOnServer {
    ...
}

I'm guessing from the names that you have some kind of web service in your solution. Might IConfigureServiceOnServer in one location refer to the actual interface defined in the service, and IConfigureServiceOnServer in the other location refer to the proxy copy defined in the service reference?

Alternatively, the ServiceConfigurator class might compile to a different type than the one actually being instantiated in your reflection code.

UPDATE:

I suggest you debug the AssemblyQualifiedName property of both the class and its interface for (a) the original defined type, and (b) the one instantiated by reflection.

I suspect the problem you are facing is that the types are loaded into different contexts. Using Assembly.LoadFrom will load the type into the LoadFrom context, while the interface you have defined I guess is in the Load context. See here for more info on the LoadFrom context.

Do you load the assemblies from different locations? If not you could try using Assembly.Load to load the assembly using the display name, this should load the type into the same context as the interface and your cast should work since the type identities will hopefully match. If this works, you might be better off just using the assembly qualified name and using Type.GetType to load the type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM