【问题标题】:How to dynamically extend C# class with new methods如何使用新方法动态扩展 C# 类
【发布时间】:2011-10-06 03:45:38
【问题描述】:

我正在用 ASP.NET 构建一个网站,该网站允许基于公共类创建新模块。新模块需要能够使用自己的方法/函数库来扩展基类。我想在 Application_Start 加载所有模块。它们由唯一的字符串键标识。

结构是这样的:

根 -斌 --module1.dll --module2.dll -模块 --模块1 ---mod.key1 --模块2 ---mod.key2

在启动时读取每个模块文件夹并识别它的密钥,从数据库加载所有设置并设置公共属性,然后存储在一个集合中。当一个页面被请求一个模块时,基页面类使用它的唯一目录键加载适当的模块。问题是基本模块类不包含特定于该模块的方法库(只有它是从 db 加载的属性/设置)。如何扩展模块类以在启动时模块加载期间包含方法,或者只是使用它的字符串名称动态实例化正确的扩展类?或任何其他想法?我不想在应用加载方法中硬编码类名,以便它可以扩展以添加未来的模块。

【问题讨论】:

    标签: c# asp.net dynamic


    【解决方案1】:

    有几种方法可以做到这一点。一种方法是创建要从中继承的基类或接口,在另一个 DLL 中编写后代类,然后根据需要使用 Assembly.LoadFrom() 方法从 DLL 加载适当的类。

    public MyType LoadTypeFromAssembly(string assemblyPath, string typeName)
    {
                var assembly = Assembly.LoadFrom(assemblyPath);
    
                if (assembly == null)
                    throw new InvalidOperationException("Could not load the specified assembly '" + assemblyPath + "'");
    
                var type = assembly.GetType(typeName);
                if (type == null)
                    throw new InvalidOperationException("The specified class '" + typeName + "' was not found in assembly '" + assemblyPath  + "'");
    
                var instance = (MyType)Activator.CreateInstance(type);
                return instance;
    }
    

    其中MyType 是您的基类或接口的类型,typeName 是您的后代类的名称(继承自 MyType)。

    【讨论】:

    • 酷,我试试看,然后我需要在类似 MyDerivedType derivedType = (MyDerivedType)MyCollection["my.key"]; 的代码中使用它派生类型.MyMethod();
    • 似乎可以工作,但它需要一个构造函数参数的选项。 @Robert,这可以在 Medium Trust 中运行吗?
    【解决方案2】:

    这可能对你有帮助,我有一个 @Robert 所说的模型。

    我必须根据数据库中的条目切换到我的业务层。

    如果数据库中有自定义业务层 dll 的条目,我必须从数据库表中为自定义程序集指定的路径加载,否则我必须从我的网站 bin 文件夹中的默认业务层加载类。

    namespace BO.Factory
        {
            public class CFactory
            {
    
                public static object getClassInstance(string key, params  object[] constructorArgs)
                {
                    try
                    {
                        string assemblyPath = null;
                        string customClassName = null;
                        DataSet objDataset = getAssemblyInfo(key);
                        if (objDataset != null && objDataset.Tables.Count > 0 && objDataset.Tables[0].Rows.Count > 0)
                        {
                            assemblyPath = objDataset.Tables[0].Rows[0]["ACA_ASSEMBLY_PATH"].ToString();
                            customClassName = objDataset.Tables[0].Rows[0]["ACA_CLASS_NAME"].ToString();
                        }
    
                        Assembly assembly;
                        Type type;
                        string className;
    
                        if (assemblyPath != null && assemblyPath != string.Empty)
                        {
                            assembly = Assembly.LoadFile(assemblyPath);
                            className = customClassName;
                        }
                        else // if no customisation
                        {
                            assembly = key.Split('.')[1].ToString() == "BO" ? typeof(Catalyst.BO.SchoolBO.CSchoolBO).Assembly : typeof(Catalyst.DAL.SchoolDAO.CSchoolDAO).Assembly;
                            className = key;
                        }
    
                        type = assembly.GetType(className, true, true);
    
                        object classInstance = constructorArgs == null ? Activator.CreateInstance(type) : Activator.CreateInstance(type, constructorArgs);
                        if (classInstance == null) throw new Exception("broke");
                        return classInstance;
                    }
                    catch (Exception e)
                    {
                        throw (e);
                    }
    
                }
    
                static DataSet getAssemblyInfo(string key)
                {
                    try
                    {
                        string cmdText = "SELECT ACA_ID,ACA_KEY,ACA_ASSEMBLY_PATH,ACA_CLASS_NAME "
                                        + "FROM ADM_CUSTOM_ASSEMBLY_INFO "
                                        + "WHERE ACA_KEY='" + key + "'";
    
                        System.Data.SqlClient.SqlCommand sqlcommand = new System.Data.SqlClient.SqlCommand(cmdText);
    
                        DAL.DBHelper.CDBHelper objCDBHelper = new Catalyst.DAL.DBHelper.CDBHelper();
    
                        return objCDBHelper.PopulateDS(sqlcommand);
                    }
                    catch
                    {
                        return null;
                    }
    
                }
            }
        }
    

    我的默认类和自定义类都继承自一个通用接口,该接口与其中定义的所有通用方法一样。

    【讨论】:

      猜你喜欢
      • 2010-11-14
      • 2017-05-08
      • 1970-01-01
      • 1970-01-01
      • 2012-11-22
      • 1970-01-01
      • 1970-01-01
      • 2013-01-18
      • 1970-01-01
      相关资源
      最近更新 更多