在c#中添加对动态文件加载器的支持

时间:2013-10-10 13:00:33

标签: c# filereader

如果我在C#中有一个控制台应用程序读取某种格式的文件并将它们转换为业务对象,我通过设置IReader接口来设计它,以便我可以支持不同的格式,例如XML,CSV,管道分隔等,并为每种文件格式设置不同的具体类。

如果要求是能够动态加载新文件阅读器(新格式)而无需重新编译,那么我有办法实现这一目标吗?

我能想到的唯一方法是以某种方式使用XSD或reg表达式,但在我看来应该有更好的解决方案

3 个答案:

答案 0 :(得分:0)

这听起来像你想要一个动态加载你的IReaders的插件机制。那里有很多例子。

Simple plugin mechanism sample

SO discussion

答案 1 :(得分:0)

你可以使用反射。 IReader的每个实现都可以使用不同的DLL。您还可以创建一个属性来标记IReader的每个实现,该实现指出它处理的文件格式。

public sealed class InputFormatAttribute : Attribute
{
    private string _format;
    public string Format
    {
        get { return format; }
    }
    public InputFormatAttribute(string format)
    {
        _format = format;
    }
}

[InputFormat("CSV")]
public class CSVReader : IReader
{
    // your CSV parsing code here
    public BusinessObject Parse(string file)
    {}
}



BusinessObject LoadFile(string fileName)
{
    BusinessObject result = null;
    DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
    FileInfo[] pluginList = dirInfo.GetFiles("*.DLL");

    foreach (FileInfo plugin in pluginList)
    {
        System.Reflection.Assembly assem = System.Reflection.Assembly.LoadFile(fileInfo.FullName);
        Type[] types = assem.GetTypes();
        Type type = types.First(t => t.BaseType == "IReader");

        object[] custAttrib = type.GetCustomAttributes(typeof(InputFormatAttribute), false);
        InputFormatAttribute at = (InputFormatAttribute)custAttrib[0];

        if (at.Format.Equals(Path.GetExtension(fileName).Substring(1), StringComparison.CurrentCultureIgnoreCase))
        {
            IReader reader = (IReader)assem.CreateInstance(type.FullName);
            return reader.Parse(fileName);
        }

    }

    // got here because not matching plugin found
    return null;

}

答案 2 :(得分:0)

取决于读者的共谋,您可以决定使用CodeDom让某人直接编写代码。简短的例子:

            // create compiler
            CodeDomProvider provider = CSharpCodeProvider.CreateProvider("C#");
            CompilerParameters options = new CompilerParameters();
            // add more references if needed
            options.ReferencedAssemblies.Add("system.dll");
            options.GenerateExecutable = false;
            options.GenerateInMemory = true;
            // compile the code
            string source = "using System;namespace Bla {public class Blabla { public static bool Test { return false; }}}";
            CompilerResults result = provider.CompileAssemblyFromSource(options, source);
            if (!result.Errors.HasErrors)
            {
                Assembly assembly = result.CompiledAssembly;
                // instance can be saved and then reused whenever you need to run the code
                var instance = assembly.CreateInstance("Bla.Blabla");
                // running some method
                MethodInfo method = instance.GetType().GetMethod("Test"));
                var result = (bool)method.Invoke(_formulas, new object[] {});
            }

但可能你必须提供某种编辑器或部分完成任务(因此只需编写必要的代码)。