-1

我需要使用需求动态加载类的实例并将其转换为各种基本类型。现在,在阅读并尝试一些示例时,我发现在运行时处理类时,我可能不了解我需要了解的所有内容。

我有一种情况,抽象类 B 实现接口 A。现在 B 类是 C 类的基类。当我在运行时动态加载包含所有 3 种类型的程序集时,我希望我应该能够使用 Load从上下文中,加载程序集,创建类 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;
        }
    }

我的解决方案的图像,以帮助那些到目前为止理解问题的人

4

2 回答 2

2

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

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

于 2013-02-26T02:54:44.690 回答
1

我认为阿列克谢列文科夫是正确的。你加载你的 TestSandBox.dll 两次。一次作为对您的项目的引用,第二次通过 Assembly.LoadFrom。根据您自己链接的文档,这可能会导致意外行为。这是一个报价供您参考:

如果使用 LoadFrom 加载程序集,并且探测路径包括具有相同标识但位置不同的程序集,则可能会发生 InvalidCastException、MissingMethodException 或其他意外行为。

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

于 2013-02-27T02:04:43.423 回答