要件があります: 1. 任意のタイプのオブジェクトをリストに格納する必要がある 2. 呼び出しのキャストをできるだけ避ける
そのために、私は何かを考え出そうとしました。何を試しても、ボクシング\アンボクシングを取り除くことはできませんでした。あなたの誰かがそれを達成する何かに出くわしたかどうか知りたかった.
私が作成したクラスは、メモリとパフォーマンスの点で ArrayList の 1.5 倍かかるため、小さなコレクションを扱っていない限り、ほとんど役に立ちません。それらの少なくとも 1 つ (できればパフォーマンス) も改善する方法を見つけようとしています。
フィードバックをお待ちしております。
public class Castable
{
Object _o;
public override bool Equals(object obj) { return base.Equals(obj); }
public override int GetHashCode() { return base.GetHashCode(); }
public bool Equals<T>(T obj)
{
T v1 = (T)this._o;
//T v2 = obj;
//var v2 = obj; // Convert.ChangeType(obj, obj.GetType());
// This doesn't work.. (Cannot convert T to Castable
//var v2 = Convert.ChangeType(this.GetType() == obj.GetType() ?
//((Castable)obj)._o.GetType(), obj.GetType());
//if (((T)this._o) != obj) //<== why this doesn't work?
//if (v1 == obj) //<== "Operator '==' cannot be applied to operands of type 'T' and 'T'"
if(v1.Equals(obj))
{
return true;
}
return false;
}
public bool Equals(Castable obj)
{
var v = Convert.ChangeType(obj._o, obj._o.GetType());
return Equals(v);
}
public static bool operator ==(Castable a, Castable b)
{
return a.Equals(b);
}
public static bool operator !=(Castable a, Castable b)
{
return !a.Equals(b);
}
#region HOW CAN WE USE GENRIC TYPE FOR == and != OPERATOR?
public static bool operator ==(Castable a, object b)
{
return a.Equals(b);
}
public static bool operator !=(Castable a, object b)
{
return !a.Equals(b);
}
#endregion
public void Set<T>(T t) { _o = t; }
public T Get<T>() { return (T)_o; }
public static long TestLookup(IList list, int elements, int lookups)
{
object value;
Stopwatch watch = new Stopwatch();
watch.Start();
for (long index = 0; index < lookups; ++index)
{
value = list[random.Next(0, elements - 1)];
}
watch.Stop();
return watch.ElapsedMilliseconds;
}
public static long TestCompare(IList list, int elements, int lookups)
{
//object value;
bool match;
Stopwatch watch = new Stopwatch();
watch.Start();
for (long index = 0; index < lookups; ++index)
{
match = random.Next() == (int)list[random.Next(0, elements - 1)];
}
watch.Stop();
return watch.ElapsedMilliseconds;
}
public static long TestCompareCastable(IList<Castable> list, int elements, int lookups)
{
//object value;
bool match;
Stopwatch watch = new Stopwatch();
watch.Start();
for (long index = 0; index < lookups; ++index)
{
match = list[random.Next(0, elements - 1)] == random.Next(); //most of the times 1.4 times
//match = list[random.Next(0, elements - 1)].Equals(random.Next()); // may be 1.3 times ArrayList
}
watch.Stop();
return watch.ElapsedMilliseconds;
}
public static void Test(int elements, int lookups, int times)
{
List<int> intList = new List<int>();
List<Castable> castableList = new List<Castable>();
ArrayList intArrayList = new ArrayList();
if (Stopwatch.IsHighResolution)
Console.WriteLine("We have a high resolution timer available");
long frequency = Stopwatch.Frequency;
Console.WriteLine(" Timer frequency in ticks per second = {0}", frequency);
for (int index = 0; index < elements; ++index)
{
intList.Add(random.Next());
intArrayList.Add(random.Next());
Castable c = new Castable();
c.Set(random.Next());
castableList.Add(c);
}
long ms = 0;
string result = "";
string ratios = "";
for (int time = 0; time < times; ++time)
{
ms = TestLookup(intList, elements, lookups);
result += "intList Lookup Time " + ms.ToString() + " MS\n";
ms = TestLookup(castableList, elements, lookups);
result += "intArrayList Lookup Time " + ms.ToString() + " MS\n";
ms = TestLookup(intArrayList, elements, lookups);
result += "castableList Lookup Time " + ms.ToString() + " MS\n";
ms = TestCompare(intList, elements, lookups);
result += "intList Compare Time " + ms.ToString() + " MS\n";
long msarraylist = ms = TestCompare(intArrayList, elements, lookups);
result += "intArrayList Compare Time " + ms.ToString() + " MS\n";
ms = TestCompareCastable(castableList, elements, lookups);
result += "castableList Compare Time " + ms.ToString() + " MS\n";
ratios += String.Format("round: {0}, ratio: {1}\n", time, (float)ms / msarraylist);
}
//MessageBox.Show(result);
MessageBox.Show(ratios);
int i = 10;
Castable o1 = new Castable();
o1.Set(i);
int j = 10;
Castable o2 = new Castable();
o2.Set(j);
if (!o1.Equals(10))
{
Console.WriteLine("unequal");
}
if (!o1.Equals(o2))
{
Console.WriteLine("unequal");
}
if (o1 != j)
{
Console.WriteLine("unequal");
}
int x = o1.Get<int>();
}
}
編集
要するに、私は達成しようとしています:
@ winSharp93: はい、要するに: List GenericGenericCollection = new List ();
GenericGenericCollection.Add(新しい文字列("ソネット");
GenericGenericCollection.Add(42);
GenericGenericCollection.Add(新しい MyOwnCustomType);
もう一度編集
私が見つけた 2 つの方法があります。 1. .NET 4 では、新しい「dynamic」キーワードが導入されています。に行Object _o;
を差し替えればdynamic _o;
そのままコードが使えます。問題は、 dynamic が動的タイプであるはずですが、パフォーマンスはボクシングのようです..
一般的な == 演算子に依存する代わりに、暗黙的 (私が好む) または明示的なキャスト演算子を追加することで、パフォーマンスを向上させることができます。
http://igoro.com/archive/fun-with-c-generics-down-casting-to-a-generic-type/に基づいて、次のクラスを追加しました。これにより、ボックス化とパフォーマンスが処理されます。次のクラスのパフォーマンスは、int または Castable の ArrayList よりもわずかに優れています。もちろん、
List<int>
比較すると先は長いです。私の観点からの唯一の問題は、オブジェクトがプレーンな Any オブジェクトに割り当てられて、具体的な型が内部に埋め込まれていることAnyInternal<T>
です。method を持つ方法も見つかりませんでしたT Get()
。キーワード dynamic でさえ、実行時にステートメントで失敗します。
Any.AnyInternal<dynamic> any = (Any.AnyInternal<dynamic>)anyInstanceContainingAnyInternalForInt;
//too bad I can't seal Any after AnyInternal<T> has derived from it.
public abstract class Any
{
public static implicit operator int(Any any)
{
return Any.ToType<int>(any).Data;
}
public static AnyInternal<T> ToType<T>(Any any)
{
return ((AnyInternal<T>)any);
}
public class AnyInternal<T> : Any
{
private T _data;
public T Data { get { return _data; } }
public AnyInternal(T data)
{
_data = data;
}
}
}