使用反射动态加载程序集和实例化类型

时间:2013-02-26 02:18:21

标签: c# .net reflection abstract-class

我需要使用require动态加载并将类的实例强制转换为各种基类型。现在,在阅读并尝试一些示例时,我发现在运行时使用类时,我可能无法理解所需的全部内容。

我有一种情况,抽象类B实现了接口A.现在,类B是类C的基类。当我在运行时动态加载包含所有3种类型的程序集时,我希望我能够,使用Load From上下文,加载程序集,创建一个C类实例,并将其转换为接口A的类型。但这似乎根本没有发生,我希望得到一个解释为什么。提前致谢。

http://msdn.microsoft.com/en-us/library/2xkww633.aspx

http://msdn.microsoft.com/en-us/library/1009fa28.aspx

public interface ICaseOutputGenerator
{
    String SampleProperty { get; set; }
    void Process();

}

public abstract class CaseOutputGeneratorBase : ICaseOutputGenerator
{
    public String SecondSampleProperty { get; set; }


    public virtual void SecondProcessMethod()
    {
    }

    public abstract void ThirdSampleProcessMethod();


    public string SampleProperty
    {
        get;
        set;
    }

    public void Process()
    {
        Console.WriteLine("Process in CaseOutputGeneratorBase Called");
    }
}

public class TestCaseOutputGenerator : CaseOutputGeneratorBase
{
    public override void ThirdSampleProcessMethod()
    {
        throw new NotImplementedException();
    }
}


//////////////////////////////////////////////////////////////////////////////

公共类TestSandBoxManager     {

    public TestSandBoxManager()
    {


    }

    public String ProcessAssemblyByFullDisplayName(String assemblyFullDisplayName)
    {
        String temp = String.Empty;
        var casecust = GetAssemblyByFullDisplayName(assemblyFullDisplayName);
        if (casecust != null)
            temp = ("Cast Passed");
        else
            temp = ("Cast Failed");

        return temp;

    }


    public String ProcessFile(String assemblyName, String className)
    {
        String temp = String.Empty;
        var casecust = GetCaseOutputGeneratorObject(assemblyName, className);
        if (casecust != null)
            temp=("Cast Passed");
        else
            temp=("Cast Failed");

        return temp;

    }

    private static object GetAssemblyByFullDisplayName(string fullName)
    {
        try
        {
            Type caseOutputGen = null;
            String fullQualifiedName = String.Empty;
            var localAssembly = Assembly.LoadFrom(fullName);

            foreach (var testType in localAssembly.GetTypes())
            {

                if ( testType.FullName != fullName)
                    continue; 
                fullQualifiedName = testType.FullName;
                break;
            }
            if (fullQualifiedName == null)
                return null;

            var obj = Activator.CreateInstance(Type.GetType(fullQualifiedName));
            return obj;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }



    public String ProcessFile2(String assemblyName, String className)
    {
        String temp = String.Empty;
        var casecust = GetCaseOutputGeneratorObjectLoadFrom(assemblyName, className);
        if (casecust != null)
            temp = ("Cast Passed");
        else
            temp = ("Cast Failed");

        return temp;

    }

    public static ICaseOutputGenerator GetCaseOutputGeneratorObject(string assemblyName, string className)
    {
        ICaseOutputGenerator caseOutputGen = null;

        var obj = GetObject(assemblyName, className);
        if (obj != null)
            caseOutputGen = (ICaseOutputGenerator)obj; // FAILS HERE
        return caseOutputGen;
    }

    public static ICaseOutputGenerator GetCaseOutputGeneratorObjectLoadFrom(string assemblyName, string className)
    {
        ICaseOutputGenerator caseOutputGen = null;

        try
        {
            var obj = GetObject2(assemblyName, className);
            if (obj != null)
                caseOutputGen = (ICaseOutputGenerator)obj; // FAILS HERE
        }
        catch (Exception ex)
        { 
            throw ex;
        }
        return caseOutputGen; 
    }

    private static object GetObject2(string fullName, string className)
    {
        try
        {
            Type caseOutputGen = null;
            String fullQualifiedName = String.Empty;
            var localAssembly = Assembly.LoadFrom(fullName);

            foreach (var testType in localAssembly.GetTypes())
            {

                if (!testType.FullName.EndsWith(className, StringComparison.InvariantCultureIgnoreCase)) 
                continue;
                caseOutputGen = testType;
                fullQualifiedName = testType.FullName;
                break;
            }
            if (caseOutputGen == null) 
                return null;

            var obj = Activator.CreateInstanceFrom(fullName, fullQualifiedName);
            return obj.Unwrap();
        } 
        catch (Exception ex)
        {
            throw ex;
        }
    }


    private static object GetObject(string fullName, string className)
    {
        try
        {
            Type caseOutputGen = null;
            var localAssembly = Assembly.LoadFrom(fullName);
            foreach (var testType in localAssembly.GetTypes())
            {
                if (!testType.FullName.EndsWith(className, StringComparison.InvariantCultureIgnoreCase)) continue;
                caseOutputGen = testType;
                break;
            }
            if (caseOutputGen == null) return null;

            var obj = Activator.CreateInstance(caseOutputGen);
            return obj;
        }
        catch (FileNotFoundException ex)
        {
            throw new Exception("Failed to load assembly: " + Environment.NewLine + fullName, ex);
        }
        catch (Exception ex)
        {
            throw new Exception("Failed to load assembly: " + Environment.NewLine + fullName, ex);
        }
    }
}

//////////////////////////////////////////////////////////////////////////////

public Boolean testReflection2()
    {
        try
        {
            //create an instance of the testsandboxmanager
            TestSandBoxManager t = new TestSandBoxManager();
            String ret = t.ProcessFile2(@"...\Documents\visual studio 2012\Projects\TestSandBox\TestSandBox\bin\Debug\TestSandBox.dll", "TestCaseOutputGenerator");
            Console.WriteLine(ret);
            Console.ReadLine();

            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

IMage of my solution to help those who understand the question so far

2 个答案:

答案 0 :(得分:2)

很可能你有2 ICaseOutputGenerator - 每个集会中有一个。即使代码相同,也不能将对象/接口转换为另一个程序集中类似命名的接口。您可以通过查看调试器中创建的对象来检查创建对象是否从其自己的程序集实现ICaseOutputGenerator这一事实。

如果是这种情况,您需要弄清楚要放置ICaseOutputGenerator接口的位置,以便它来自“自定义加载程序集”和您的主应用程序的同一程序集。通常,共享接口在单独的程序集中实现,并链接到所有“插件”程序集以及应用程序程序集。

答案 1 :(得分:1)

我认为阿列克谢莱文科夫是个好消息。您加载TestSandBox.dll两次。一次作为项目的参考,第二次通过Assembly.LoadFrom。根据{{​​3}},这可能会导致意外行为。以下是您引用的引用:

  

如果装配有LoadFrom,并且探测路径包含   具有相同身份但位置不同的集会   InvalidCastException,MissingMethodException或其他意外   行为可能会发生。

这正是您案件中发生的事情。如果更改加载程序集的路径指向与主可执行文件相同的文件夹,它将正常工作。