ここでお手伝いできるかどうかを見てみましょう。
私が間違っていると私を修正しますが、入力ファイルと出力ファイルのすべてに列と列のみのデータが含まれているようです。
その場合、X入力列をY出力列に変換するという問題を想像してみてください。クライアントごとに、トランスフォームを指定する構成が必要です。設定は次のようになります
Y1 = X1
Y2 = X1 + X2
Y3 = X3 + " some string"
ご覧のとおり、設定行は単純にC#式です。 LINQ Expression classを使用して、変換式から式ツリーを構築することができます。 Expressions hereについて学ぶことができます。これらの式をコンパイルして、実際の変換を行うために使用することができます。 C#に関して考えると、リストを入力として受け取り、各クライアントの出力としてリストを返す静的変換メソッドを構築します。式を使用する場合は、構成ファイルを自分で解析する必要があります。
適切なC#構文をサポートできるRoslyn Compiler Servicesを使用することもできます。このように、文字通り変換を行うことができる静的メソッドを持つことができます。これにより、解析の任務が軽減されます。
どちらの場合でも、次のようなことに対処する必要があります:列が文字列であると期待する必要がありますか(必要な列を解析して必要な列を数値に解析する必要があります)数字のような数字を自動的に数字に変換します(これは特別な設定をする必要はありませんが、IDのような数字を持つ列を扱うときに問題になるかもしれませんが、不適切な取り扱いを避けるため文字列として扱わなければなりません)。 。要約すると
、私のアプローチは次のとおりです。
- クライアントごとに設定ファイルを作成します。
- 式をC#メソッドに動的に変換する
- この設定を生成するためのGUIを提供します。特殊な構文(式)またはC#構文(Roslyn)を知らなくてもサポートを簡単に指定できます。 。 configを保存するときは、クライアントごとに1つのアセンブリ(またはクライアントごとに別々のアセンブリ)で1つのメソッドを生成し、永続化することができます。それをクライアントライブラリと呼ぶことにしましょう。
- メインアプリケーションは、Excel、Validatingなどの標準的な読み込みをすべて実行してから、クライアントライブラリメソッドを呼び出して、メインアプリケーションでさらに処理できる標準形式の出力を生成することができます。
あなたは要点を持っていますか?
編集:デモンストレーションするコードを追加してください。コードは少し長めですが、理解のためにコメントしました。
// this data represents your excel data
var data = new string[][] {
new string [] { "col_1_1", "10", "09:30" },
new string [] { "col_2_1", "12", "09:40" }
};
// you should read this from your client specific config file/section
// Remember: you should provide a GUI tool to build this config
var config = @"
output.Add(input[0]);
int hours = int.Parse(input[1]);
DateTime date = DateTime.Parse(input[2]);
date = date.AddHours(hours);
output.Add(""Custom Text: "" + date);
";
// this template code should be picked up from a
// non client specific config file/section
var code = @"
using System;
using System.Collections.Generic;
using System.Linq;
namespace ClientLibrary {
static class ClientLibrary {
public static List<string> Client1(string[] input) {
var output = new List<string>();
<<code-from-config>>
return output;
}
}
}
";
// Inject client configuration into template to form full code
code = code.Replace(@"<<code-from-config>>", config);
// Compile your dynamic method and get a reference to it
var references = new MetadataReference[] {
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
};
CSharpCompilation compilation = CSharpCompilation.Create(
null,
syntaxTrees: new[] { CSharpSyntaxTree.ParseText(code) },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
MethodInfo clientMethod = null;
using (var ms = new MemoryStream()) {
EmitResult result = compilation.Emit(ms);
if (!result.Success) {
foreach (Diagnostic diagnostic in result.Diagnostics) {
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
} else {
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
clientMethod = assembly.GetType("ClientLibrary.ClientLibrary").GetMethod("Client1");
}
}
if (clientMethod == null)
return;
// Do transformation
foreach (string[] row in data) {
var output = clientMethod.Invoke(null, new object[] { row }) as List<string>;
Console.WriteLine(string.Join("|", output));
}
あなたが気づくと、心配する唯一の作品はの自動生成コードにGUIで
nuget install Microsoft.Net.Compilers # Install C# and VB compilers
nuget install Microsoft.CodeAnalysis # Install Language APIs and Services
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
これをコンパイルするには、いくつかのnugetライブラリを必要とし、それらに対応する使用条項ます私はここで提供していません。単純な変換が必要な場合は非常に簡単ですが、複雑な変換の場合はもっと複雑になります
ファイル全体で繰り返すことのできるパターンを特定できない場合は、手動でフォーマットを行う方がよい場合があります。すべての顧客に均一なテンプレートを提供する方法はありますか? Excelからデータをインポートしようとしていますか?なぜC#タグがリストされているのか分かりません。スプレッドシートに列を挿入して式を変更するコードを書くのは簡単ですが、完全に動的な変更が必要な場合は、さらに難しくなり(無意味になります)たぶん私はあなたがしようとしていることを正確に理解していません。 –
これはあなたが探している答えか、どんな制約があるのか分かりませんが、私たちが通常行っていることは、顧客が使用するための標準テンプレートを提供することによって入力を標準化することです。 – ainwood