创建动态自定义选择器

时间:2015-10-06 10:42:52

标签: filehelpers

我有一个带有CustomSelector的MultiRecordEngine,其中我试图以不同的字符串开头循环许多行

而不是像这样的'ifs'的长列表(工作正常):

if (recordLine.Length == 0)
    return null;
if (recordLine.StartsWith("EDI_DC40_U"))
    return typeof(IDOC_EDI_DC40_U);
if (recordLine.StartsWith("E2EDL22"))
    return typeof(IDOC_E2EDL22);
[...(some more ifs)...] 
else
    return null;

我想尝试一些更有趣的东西。对于每种可能的行,在其名称中都有一个带有行前缀的类,我想这样做:

if (recordLine.Length == 0)
    return null;

foreach(Type type in GetIDOCTypes()) {
    // remove class prefix (IDOC_) from type name
    string name = type.Name.Substring(6,type.Name.Length - 5);

    if (recordLine.StartsWith(name))
        return type;
}

return null
  

{“你必须在foreach循环中使用引擎之前调用BeginRead。”} System.Exception {FileHelpers.FileHelpersException}

当我这样做时,我得到了Filehelper异常,我只是不知道如何,何时何地应该调用'BeginRead'......

我的做法完全错了吗?

这是我的sample project

谢谢!

1 个答案:

答案 0 :(得分:1)

你有一个我可以看的样本项目吗?除非您正在访问引擎记录数组,否则肯定没有什么可以阻止您专门执行此操作但我怀疑您实际返回的是null而不是默认类型,因此它不知道您拥有的记录类型。

必须调用BeginRead才能以异步方式开始解析文件。您实际上还没有发布代码来说明您是如何阅读数据的。我现在正打电话,但你必须有类似的东西:

var engine = new MultiRecordEngine(typeof (Orders),
typeof (Customer),
typeof (SampleType));

engine.RecordSelector = new RecordTypeSelector(CustomSelector);

var res = engine.ReadFile("Input.txt");

此时引擎将以同步模式开始循环遍历记录,调用自定义选择器。

诊断

错误处理

所以我看了一下示例项目,看来我没有确定问你是否检查了内部异常。您从测试项目中获得的完整错误是:

System.Exception was unhandled
  HResult=-2146233088
  Message=Selector failed to process correctly
  Source=FileHelpers
  StackTrace:
       at FileHelpers.MultiRecordEngine.ReadStream(IRecordReader reader)
       at FileHelpers.MultiRecordEngine.ReadFile(String fileName)
       at FileHelpersLoopTest.IDOCFileClass.readIDOCFile()
       at FileHelpersLoopTest.Program.Main(String[] args)
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
       HResult=-2146233086
       Message=Index and length must refer to a location within the string.
Parameter name: length
       ParamName=length
       Source=mscorlib
       StackTrace:
            at System.String.Substring(Int32 startIndex, Int32 length)
            at FileHelpersLoopTest.IDOCFileClass.CustomSelector(MultiRecordEngine engine, String recordLine)
            at FileHelpers.MultiRecordEngine.ReadStream(IRecordReader reader)
       InnerException: 

这应该立即从内部异常中给出一个提示,因为堆栈跟踪说它失败了"索引和长度必须引用字符串中的位置。从 CustomSelector 调用的 System.String.Substring 中的参数名称:length" 显示它确实已到达您的代码,但您使用了一些不正确的索引,即字符串的长度。

另外,我注意到你正在检查RecordLine的长度,但不是它是否为null,因此可能会出现另一个错误。我建议使用 System.String.IsNullOrWhiteSpace 来检查长度是否安全。

工作代码

以下对我来说很好,但您仍然需要将IODC类型与文件中的EDI类型进行匹配。我尝试添加EDI_前缀,但类型仍然不匹配,因此我将该部分留给您,因为我假设这只是样本数据或命名问题。

     // Failing code block 
        if (string.IsNullOrWhiteSpace(recordLine))
            return null;

        var types = GetIDOCTypes();
        foreach (Type type in types)
        {
            // remove class prefix (IDOC_) from type name
            string name = "EDI_" + type.Name.Substring(6, type.Name.Length - 5);

            Console.WriteLine($"{name} vs {recordLine.Substring(0, name.Length)}");
            if (recordLine.StartsWith(name))
                return type;
        }
        return null;
        // END Failing code block