- - PR -
型定義のみが異なる複数のクラス(C#)
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2003-07-22 00:41
型定義のみが異なり制御ロジックが同じ複数のクラスをスマートに表現する方法は
ありますか? 1.同じ制御ロジックを複数箇所に書くのは保守面で良くない。 2.いくつかの型については処理効率を重視するため厳密に区別したい。 この2つの条件を両立させる方法を知りたいと思っています。 本当はもっと複雑なのですがわかりやすくするために下記の例をあげます。 using System; namespace test { // 質問 // 制御ロジックは同一で変数の型だけが異なる2つのクラスがあった場合 // 同じ制御ロジックを2つ記述するのは保守の面で問題があります。 // 制御ロジックを1つにするスマートな記述方法はあるでしょうか? // 前提 // double型のbufferでbyte型とdouble型の両方を格納すれば解決できますが、 // 今回の趣旨としては無しです。 public class ClassStatistics { // バイト型のクラス // bufferはbyte[]型でsum_xはint型で定義する public class ClassByteSigma { private byte[] buffer; private int number; private int sum_x; public ClassByteSigma() { buffer = new byte[1000]; number = 0; sum_x = 0; } public void Add(byte x) { sum_x += x; number++; } public int Number() { return number; } public double Average() { return (double)sum_x/number; } } // 倍精度型のクラス // bufferはdouble[]型でsum_xはdouble型で定義する public class ClassDoubleSigma { private double[] buffer; private int number; private double sum_x; public ClassDoubleSigma() { buffer = new double[1000]; number = 0; sum_x = 0; } public void Add(double x) { sum_x += x; number++; } public int Number() { return number; } public double Average() { return sum_x/number; } } } } | ||||
|
投稿日時: 2003-07-22 08:09
C++ならば、templateってところでしょうが...
独自interfaceを定義して、そのinterfaceからbyte型とdouble型の型を定義してみてはいかがでしょう? MyInterface -+- MyByte | +- MyDouble | ||||
|
投稿日時: 2003-07-22 12:36
次のメジャーバージョンアップの際に取り込まれることになっているジェネリクスに期待、ってとこでしょうか。。。
http://www.microsoft.com/japan/msdn/vs/vcsharp/vbconCProgrammingLanguageFutureFeatures.asp | ||||
|
投稿日時: 2003-07-22 17:21
ご返答ありがとうございます。未だインターフェースを使ったことがないので、
ちょっと勉強してみます。(C#)
| ||||
|
投稿日時: 2003-07-22 18:52
伊藤さんのサンプルよりももう少し複雑な場合で、アルゴリズムと、実装の関係を設計的にすっきりさせたいのであればtemplate methodパターン(デザインパターン)を使うところだと思います。
後は、あまりやりたくないのですが、オブジェクト型の引数と戻り値を持つメソッドを作ってしまって、そのメソッドを使う側で戻り値をキャストさせる方法もあります。(まぁこれが大変問題のある方法だというのはわかります。でもGenericsサポートまではこんな方法で逃げるしかないのかもしれません。) _________________ いしさかただひろ(*^^)v | ||||
|
投稿日時: 2003-07-22 22:56
こんばんは、meiです。
CodeDomを使った遊び。 ※注、Managed C# Compilerへの参照が必要です。 // ひな形ソースから、int型クラスとdouble型クラスを作ってみる例 using System; using System.CodeDom.Compiler; using System.Reflection; public class ArrayTemplate { // テンプレートコード private const string code = @" using System; public class XXXArray { private XXX[] buffer; private XXX sum_x; private int number; public XXXArray() { buffer = new XXX[1000]; number = 0; sum_x = 0; } public void Add(XXX x) { buffer[number++] = x; sum_x += x; } public int Number() { return number; } public double Average() { return (double)sum_x/number; } }"; public static object Create(Type type) { // ソースコードのXXXをtype型に置換 string src = code.Replace("XXX", type.Name); // メモリ上でコンパイル ICodeCompiler cc = new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler(); CompilerParameters cp = new CompilerParameters(); cp.ReferencedAssemblies.AddRange(new string[] {"mscorlib.dll","System.dll"}); cp.GenerateInMemory = true; CompilerResults cr = cc.CompileAssemblyFromSource(cp, src); if(cr.Errors.HasErrors) { return null; } // インスタンスを返す return cr.CompiledAssembly.CreateInstance(type.Name + "Array"); } } // メインクラス class MyApp { static void ArrayTest(object arr, params object[] args) { MethodInfo add = arr.GetType().GetMethod("Add"); MethodInfo num = arr.GetType().GetMethod("Number"); MethodInfo ave = arr.GetType().GetMethod("Average"); foreach (object o in args) add.Invoke(arr, new object[] {o}); Console.WriteLine("Number : " + num.Invoke(arr, null)); Console.WriteLine("Average : " + ave.Invoke(arr, null)); } static void Main(string[] args) { // int型のArrayクラスを生成 object iArr = ArrayTemplate.Create(typeof(int)); // double型のArrayクラスを生成 object dArr = ArrayTemplate.Create(typeof(double)); // テスト Console.WriteLine(iArr.GetType().Name); ArrayTest(iArr, 1,1,2,3,5); Console.WriteLine(dArr.GetType().Name); ArrayTest(dArr, 1.1,2.2,3.3,4.4); } } 面倒なので実際には使えないけど(笑) | ||||
|
投稿日時: 2003-07-23 08:35
ArrayTemplateすごいですね。
ふと、(データをコードとして扱える)Lispを思い出しました。 | ||||
|
投稿日時: 2003-07-23 09:56
簡単な例(Max)でいろいろ作ってみました。
Max3は美しくないな。 |