创建动态自定义选择器
Create dynamic custom selector
我有一个带有 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;
我想尝试一些更花哨的东西。对于每种可能的行,在其名称中都有一个带有行前缀的 class,我想这样做:
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
{"You must call BeginRead before use the engine in a foreach loop."} System.Exception {FileHelpers.FileHelpersException}
当我这样做时,我遇到了 Filehelper 异常,我只是不知道我应该如何、何时何地调用 'BeginRead'...
我的做法完全错误吗?
这是我的 sample project.
谢谢!
你有我可以看的示例项目吗?除非您正在访问引擎记录数组,否则肯定没有什么可以阻止您专门执行此操作,但我怀疑您实际上返回的是 null 而不是默认类型,因此它不知道您拥有什么类型的记录。
必须调用 BeginRead 才能开始以异步方式解析文件。您实际上还没有发布代码来展示您是如何读取数据的。我现在在我的 phone 上,但你必须有类似的东西:
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:
这应该立即从内部异常中给你一个提示,因为堆栈跟踪表明它失败了 "Index and length must refer to a location within the string. Parameter name: length" inside System.String.Substring 从 CustomSelector 调用表明它确实到达了您的代码,但您使用了一些不正确的索引,即字符串的长度。
此外,我注意到您检查的是 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
我有一个带有 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;
我想尝试一些更花哨的东西。对于每种可能的行,在其名称中都有一个带有行前缀的 class,我想这样做:
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
{"You must call BeginRead before use the engine in a foreach loop."} System.Exception {FileHelpers.FileHelpersException}
当我这样做时,我遇到了 Filehelper 异常,我只是不知道我应该如何、何时何地调用 'BeginRead'...
我的做法完全错误吗?
这是我的 sample project.
谢谢!
你有我可以看的示例项目吗?除非您正在访问引擎记录数组,否则肯定没有什么可以阻止您专门执行此操作,但我怀疑您实际上返回的是 null 而不是默认类型,因此它不知道您拥有什么类型的记录。
必须调用 BeginRead 才能开始以异步方式解析文件。您实际上还没有发布代码来展示您是如何读取数据的。我现在在我的 phone 上,但你必须有类似的东西:
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:
这应该立即从内部异常中给你一个提示,因为堆栈跟踪表明它失败了 "Index and length must refer to a location within the string. Parameter name: length" inside System.String.Substring 从 CustomSelector 调用表明它确实到达了您的代码,但您使用了一些不正确的索引,即字符串的长度。
此外,我注意到您检查的是 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