いくつかの計算を行うために、数値型のみの汎用クラスを作成する方法を考えています。
すべての数値型(int、double、float ...)に共通のインターフェイスがありますか?
そうでない場合、そのようなクラスを作成する最良の方法は何ですか?
更新:
私が達成しようとしている主なことは、T型の2つの変数のうち誰が大きいかをチェックすることです。
使用している.NETのバージョンは何ですか? .NET 3.5を使用している場合、 汎用演算子の実装 in MiscUtil (無料など)があります。
これには、T Add<T>(T x, T y)
などのメソッドと、さまざまなタイプの演算用のその他のバリアント(DateTime + TimeSpan
など)があります。
さらに、これはすべての組み込み、リフト、および特注のオペレーターで機能し、パフォーマンスのためにデリゲートをキャッシュします。
これがトリッキーな理由に関する追加の背景は、 ここ です。
また、dynamic
(4.0)sort-ofがこの問題を間接的に解決することを知りたい場合があります。
dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect
<
/>
に関するコメントを再確認してください-実際にはneed演算子は必要ありません。あなただけが必要です:
T x = ..., T y = ...
int c = Comparer<T>.Default.Compare(x,y);
if(c < 0) {
// x < y
} else if (c > 0) {
// x > y
}
IComparable<T>
、IConvertible
、およびIEquatable<T>
インターフェースのような、数値型に対する操作のいくつかのインターフェースがあります。特定の機能を取得するように指定できます:
public class MaxFinder<T> where T : IComparable<T> {
public T FindMax(IEnumerable<T> items) {
T result = default(T);
bool first = true;
foreach (T item in items) {
if (first) {
result = item;
first = false;
} else {
if (item.CompareTo(result) > 0) {
result = item;
}
}
}
return result;
}
}
デリゲートを使用して、型固有の操作でクラスを展開できます。
public class Adder<T> {
public delegate T AddDelegate(T item1, T item2);
public T AddAll(IEnumerable<T> items, AddDelegate add) {
T result = default(T);
foreach (T item in items) {
result = add(result, item);
}
return result;
}
}
使用法:
Adder<int> adder = new Adder<int>();
int[] list = { 1, 2, 3 };
int sum = adder.AddAll(list, delegate(int x, int y) { return x + y; });
クラスにデリゲートを保存し、特定のデータ型のデリゲートを設定するさまざまなファクトリメソッドを使用することもできます。そうすれば、型固有のコードはファクトリーメソッドにのみ存在します。
一番近いのは、私が恐れている構造です。コード内の数値タイプに対して、より広範なチェックを行う必要があります。
public class MyClass<T> where T : struct
(...)
算術演算に単一のインターフェースを使用する必要があるため、これを行うことはできません。 Connectには、この特定の目的のためにIArithmeticインターフェイスを追加するという多くの要求がありましたが、これまでのところ、すべて拒否されています。
これを回避するには、「Calculator」インターフェースを実装するメンバーのない構造体を定義します。 Pluto Toolkit の補間ジェネリッククラスでこのアプローチを採用しました。詳細な例として、「ベクトル」計算機の実装 here があります。これにより、汎用補間器がベクトルを処理できます。 float、double、quaternionなどにも同様のものがあります。
フレームワークBCL(基本クラスライブラリ)では、多くの数値関数(System.Mathの関数など)は、各数値型にオーバーロードを持たせることでこれを処理します。
BCLの静的Mathクラスには、クラスのインスタンスを作成せずに呼び出すことができる静的メソッドが含まれています。クラスでも同じことができます。たとえば、Math.Maxには11のオーバーロードがあります。
public static byte Max(byte val1, byte val2);
public static decimal Max(decimal val1, decimal val2);
public static double Max(double val1, double val2);
public static short Max(short val1, short val2);
public static int Max(int val1, int val2);
public static long Max(long val1, long val2);
public static sbyte Max(sbyte val1, sbyte val2);
public static float Max(float val1, float val2);
public static ushort Max(ushort val1, ushort val2);
public static uint Max(uint val1, uint val2);
public static ulong Max(ulong val1, ulong val2);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericPratice1
{
public delegate T Del<T>(T numone, T numtwo)where T:struct;
class Class1
{
public T Addition<T>(T numone, T numtwo) where T:struct
{
return ((dynamic)numone + (dynamic)numtwo);
}
public T Substraction<T>(T numone, T numtwo) where T : struct
{
return ((dynamic)numone - (dynamic)numtwo);
}
public T Division<T>(T numone, T numtwo) where T : struct
{
return ((dynamic)numone / (dynamic)numtwo);
}
public T Multiplication<T>(T numone, T numtwo) where T : struct
{
return ((dynamic)numone * (dynamic)numtwo);
}
public Del<T> GetMethodInt<T>(int ch) where T:struct
{
Console.WriteLine("Enter the NumberOne::");
T numone =(T) Convert.ChangeType((object)(Console.ReadLine()), typeof(T));
Console.WriteLine("Enter the NumberTwo::");
T numtwo = (T)Convert.ChangeType((object)(Console.ReadLine()), typeof(T));
T result = default(T);
Class1 c = this;
Del<T> deleg = null;
switch (ch)
{
case 1:
deleg = c.Addition<T>;
result = deleg.Invoke(numone, numtwo);
break;
case 2: deleg = c.Substraction<T>;
result = deleg.Invoke(numone, numtwo);
break;
case 3: deleg = c.Division<T>;
result = deleg.Invoke(numone, numtwo);
break;
case 4: deleg = c.Multiplication<T>;
result = deleg.Invoke(numone, numtwo);
break;
default:
Console.WriteLine("Invalid entry");
break;
}
Console.WriteLine("Result is:: " + result);
return deleg;
}
}
class Calculator
{
public static void Main(string[] args)
{
Class1 cs = new Class1();
Console.WriteLine("Enter the DataType choice:");
Console.WriteLine("1 : Int\n2 : Float");
int sel = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Enter the choice::");
Console.WriteLine("1 : Addition\n2 : Substraction\3 : Division\4 : Multiplication");
int ch = Convert.ToInt32(Console.ReadLine());
if (sel == 1)
{
cs.GetMethodInt<int>(ch);
}
else
{
cs.GetMethodInt<float>(ch);
}
}
}
}
コンパイル時にのみ実行することはできません。しかし、以下のように数値型のほとんどの「悪い型」を取り除くために、より多くの制約を置くことができます
class yourclass <T> where T:IComparable、IFormattable、IConvertible、IComparabe <T>、IEquatable <T>、struct {...最後に、object.GetType( ) 方法。
比較するだけの場合は、IComparable <T>だけでうまくいきます。
ジェネリック型制約を使用してそれを定義できるとは思わない。コードは、おそらくDouble.ParseまたはDouble.TryParseを使用して要件が内部的にチェックされ、それが数値かどうかを判断します。または、VB.NETが問題になっていない場合は、IsNumeric()関数を使用できます。
編集: Microsoft.VisualBasic.dllへの参照を追加し、C#からIsNumeric()関数を呼び出すことができます。