How can I create an object in NETLink from System.Collections.Generic.List

I am using NETLink and I am trying to construct the following .NET object

List<string> list = new List<string>();


My first question is how can I load System.Collections.Generic.List?

The following command:

NETTypeInfo[LoadNETAssembly["mscorlib.dll"], {"Classes"}]


shows that the class is in mscorlib. But when I enter:

NETTypeInfo["System.Collections.Generic.List"]


I am getting an error message:

LoadNETType::fail: .NET failed to load type System.Collections.Generic.List. >>


On the contrary if I try to load some other class from mscorlib.dll such as:

NETTypeInfo["System.Collections.ArrayList"]


It works fine.

What I am doing wrong here ?

My second question is how can I create Generic.List type objects with NETNew from System.Collections.Generic.List class?

Thank you

PS: I am using Mathematica 10.0 and Visual Studio 2010 on a Windows7 OS

Updated Response

The internal name of System.Collections.Generic.List is "mangled". We can see what that internal name is by using NETTypeInfo:

NETTypeInfo[LoadNETAssembly["mscorlib.dll"], "Classes", "*Generic.List*"]


We can see that the internal name is System.Collections.Generic.List1[T].

We can create objects of this type directly with NETNew provided we replace the placeholder type name T with the actual element type:

Needs["NETLink"]
InstallNET[];

$list = NETNew["System.Collections.Generic.List1[System.String]"];$list@Add["xyz"]
$list@Add["mno"]$list@Add["abc"]

$list@Sort[]$list@ToArray[]
(* {"abc","mno","xyz"} *)


Original Response

In .NET, generic types cannot be instantiated directly. We must first create a specific type that specifies the generic type parameters. This is done using Type.MakeGenericType.

First we must obtain a reference to the List type. The NETLink wrapper is not enough -- we must use GetTypeObject to recover the native .NET type object:

Needs["NETLink"]

$genericListType = LoadNETType["System.Collections.Generic.List1"] // GetTypeObject;  Note carefully that the internal class name ends with List1, as shown by the information returned by the mscorlib NETTypeInfo call exhibited in the question. We then need to load the type for the list elements. For this example, we will use the String type: $stringType = LoadNETType["System.String"] // GetTypeObject;


Now we can create a dynamic type representing a list of strings:

$stringListType =$genericListType@MakeGenericType[{$stringType}];  Finally, we can create a list of strings and operate upon it: $list = NETNew[$stringListType];$list@Add["xyz"]
$list@Add["mno"]$list@Add["abc"]

$list@Sort[]$list@ToArray[]
(* {"abc","mno","xyz"} *)


I have just discovered that there is another way to make generic types and there is an advantage in this solution that I am going to demonstrate. I will continue the example offered by WReach, this helped me really a lot to make my first steps as a newby in Mathematica NETLink ;-)

$stringListType2=LoadNETType["System.Collections.Generic.List1[System.String]"] // GetTypeObject; NETType["System.Collections.Generic.List1[T]", 28]$stringListObj=NETNew[$stringListType2];$stringListObj@Add[#]&/@{"xyz","mno","abc"};

$list@ToArray[]  How did I arrive to this solution ? Well, it is all about NETObject type checking. Suppose you want to pass the object you created as an argument of a function. How are you going to check if the formal parameter accepts the correct type, i.e. a generic list of strings ? Luckily there is the NETLinkInstanceOf function. But according to the definition it accepts either NETType expression or fully qualified class names such as the string I passed to the LoadNETType. So you can type check with the following command NETLinkInstanceOf[$list, "System.Collections.Generic.List1[System.String]"]
True


Note that if you use:

$stringListType =$genericListType@MakeGenericType[{\$stringType}]
« NETObject[System.RuntimeType]»
`

That returns NETObject instead of a NETType expression.

And the question that naturally arises is how you get the NETType from the NETObject ? Well, I could not find how, so that is how I discovered the other way around. So, is there a way to get the type of a « NETObject[System.RuntimeType]» ?