2008-01-31

Dynamic instantiation of generic types

If at first you don't succeed...Change the rules.

Once I had managed to create the implementation of IList[T] (see last post), I was faced with the problem of instantiating it dynamically. All I had was the type and a reference to the type that I wanted to substitute for T. The argument to the generic type was not fixed statically.

I tried to get System.Type.GetType(string s) to return the type:

System.Type.GetType(
'MyNameSpace.MyGenericType`1[MyOtherNameSpace.MyOtherType]');


but it simply didn't want to return my type. I finally settled for this:


Type arg = (* expression that resulted in a type reference *)
object temp = new MyGenericType[object]();
Type t = temp.GetType.
GetGenericTypeDefinition.MakeGenericType(new Type[]{arg});
object newObj = Activator.CreateInstance(
t,
new object[]{ (* constructor parameters *)} );

Anyone know a way around the Activator class to improve performance?

Implementing generic IList in Delphi.NET

If at first you don't succeed... hide your astonishment

Last night I had to implement the generic version of IList in delphi. It turned out to be a little more tricky than I had hoped... The compiler didn't always give the most helpful error messages. Anyway, here is a minimal implementation of System.Collections.Generic.IList[T] in Delphi.NET (including a custom enumerator). Just replace all square brackets with the angle brackets (couldn't figure out how to get blogger to show them).

type
TMyListImpl[T] = class(TObject, IList,
ICollection, ICollection[T], IList[T])
function IList.GetEnumerator = IList_GetEnumerator;
function IList.get_Item = IList_get_Item;
public
function IList_GetEnumerator: IEnumerator;
function GetEnumerator: IEnumerator[T];
procedure CopyTo(arr: System.Array; index: integer); overload;
procedure CopyTo(arr: array of T; index: integer); overload;
function get_SyncRoot: System.Object;
function get_IsSynchronized: Boolean;
function get_Count: integer;
procedure Add(value: T); overload;
function Add(value: TObject): integer; overload;
function ICollection_Add(value: TObject): integer;
procedure Clear;
function Contains(value: T): boolean; overload;
function Contains(value: TObject): boolean; overload;
function IndexOf(value: T): integer; overload;
function IndexOf(value: TObject): integer; overload;
procedure Insert(index: integer; value: T); overload;
procedure Insert(index: integer; value: TObject); overload;
function Remove(value: T): Boolean; overload;
procedure Remove(value: TObject); overload;
procedure RemoveAt(index: integer);
function get_IsFixedSize: Boolean;
function get_IsReadOnly: Boolean;
function get_Item(index: integer): T; overload;
procedure set_Item(index: integer; Value: T); overload;
function IList_get_Item(index: integer): TObject; overload;
procedure set_Item(index: integer; Value: TObject); overload;
property Item[index: integer]: T read get_Item write set_Item;
property IsReadOnly: Boolean read get_IsReadOnly;
property IsFixedSize: Boolean read get_IsFixedSize;
property Count: integer read get_Count;
property SyncRoot: System.Object read get_SyncRoot;
property IsSynchronized: Boolean read get_IsSynchronized;
end;

TListEnumerator[T] = class(System.Object,
IEnumerator, IEnumerator[T])
function IEnumerator.get_Current = IEnumerator_get_Current;
strict private
fList: TMyListImpl[T];
FCurrentIndex: integer;
public
constructor Create(list: TMyListImpl[T]);
function get_Current: T;
function IEnumerator_get_Current: TObject;
function MoveNext: Boolean;
procedure Dispose;
procedure Reset;
end;