DotNet in max syntax

Hi,

Long time since I’ve posted something … but lately been coding from scratch a Maxscript Dotnet pipeline and been using dotnet structure directly in maxscript enums, arrays list and dictionary. but here’s my problem I’m currently using my own dll to create me empty list and dictionary does anyone know the constructor syntax to create directly List and Dictionary in maxscript?

Best,

I think array list is:


theList = dotnetobject "System.Collections.arrayList"

Not sure about dictionary.

I recall reading somewhere that MaxScript doesn’t support generics, like Dictionary<T,T> or List<T>

I am not sure.

You might be able to store the type of a Dictionary<string, object>, for example, in a variable in your dotNet dll and then pass that through to MaxScript - using the type stored in the variable you might be able to create that in MaxScript.

Well so far it does not support the creation of them but you can use them with the “.Item” to iterate / access their value if their created with a custom dll.
To replace the typed list I’ll definitely use the “System.Collections.arrayList” tried it works well and its cool cause its an (object or variant) list :slight_smile:
Id still like to do dictionary directly cause then my re skinning script wouldn’t have extra dependence but hey nothing’s perfect thanks guys!

Well found the way to do it on cgtalk
mySuperDictionary = dotnetobject “System.Collections.Generic.Dictionary`2[System.String,System.String]”

Here’s the thread http://forums.cgsociety.org/archive/index.php/t-668343.html

For anyone using Python .NET in Maya, generics are treated the same way, ie the exact type you want needs to be bound to a specific named instance before you can use it.

Yeah, JSDude, there’s some .net to get the type of a dotnetobject in Max (classOf doesn’t work, obviously). You can use that string to initialize the type, even the really strange generic type strings they give. Also remember that you can’t iterate over items in the list, you need to turn the list into an array (myList.ToArray())

You may also have better luck with creating a helper class with static constructors. So, instead of:
myDict = DotNetObject “System.Collections.Generic.Dictionary`2[System.String,System.String]”
you’d have:
myDict = (DotNetClass “MyNameSpace.MyGenericsHelperClass”).MakeStringStringDict()
You could probably do “.MakeDict” take two Type values instead, but how one would pass that from Max to .NET I’m not sure (perhaps just a “.MakeDict (DotNetClass “System.String”) (DotNetClass “System.String”)” would work, not sure).

Hi Rob,
Yep early on I had my custom Dll to build my dictionaries but I wanted to share my script with one of our other projects here so the DotNetObject “System.Collections.Generic.Dictionary`2[System.String,System.String]” syntax is working fine. As for passing dotnet object as argument to dotnet functions in maxscript it works great to! And to iterate on dotnet list I do use the toarray but its also acessible with the .Item property but I prefer using it as array cause dont have to sdo a for to loop :wink:

FWIW, you can iterate through the contents of a .NET collection using an enumerator:


sdict = dotnetobject "System.Collections.Generic.Dictionary`2[System.String,System.Char]"

sdict.add "eh" "a"
sdict.add "bee" "b"
sdict.add "sea" "c"

it = sdict.GetEnumerator()
while it.MoveNext() do
(
	format "Key: % Value: %
" it.current.key it.current.value
)

slist = dotnetobject "System.Collections.Generic.List`1[System.String]"

slist.add "eh"
slist.add "bee"
slist.add "sea"

it = slist.GetEnumerator()
while it.MoveNext() do
(
	format "current: % 
" it.current
)


More .NET generic syntax fun…

The “System.Collections.Generic” namespace is split across (at least) two assemblies, mscorlib.dll and System.dll. I found that in order to contruct a generic container that is defined in the System.dll (like Stack, LinkedList, SortedDictionary, etc.) you must specify the type argument with the full ‘Assembly Qualified Name’

so

dotnetobject “System.Collections.Generic.LinkedList`1[System.String]”)

will fail, but

dotnetobject “System.Collections.Generic.LinkedList`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]”)

works just fine!

For convenience, you probably just want to retrieve the qualified name for any type arguments once, and do it on the fly.

Here’s a sample using the .NET generic LinkedList


stringAQN= (dotnet.gettype "System.String").AssemblyQualifiedName
llist = dotnetobject ("System.Collections.Generic.LinkedList`1[[" + stringAQN + "]]")

llist.AddFirst "AAA"
llist.AddFirst "BBB"
linkC = llist.AddLast "CCC"

it = llist.GetEnumerator()
while it.MoveNext() do format "it.current = % 
" it.current

llist.AddBefore linkC "xxx"

it = llist.GetEnumerator()
while it.MoveNext() do format "it.current = % 
" it.current

llist.Remove (llist.Find "AAA")

it = llist.GetEnumerator()
while it.MoveNext() do format "it.current = % 
" it.current

Check out System.Collections.Generic and Systems.Collections.Specialized for other collections (and remember to check which assembly they come from!)

Hey thanks for the last tip that’s pretty cool
It becomes really useful using .Net in max script when doing redistributable complex scripts.
For all my pipeline stuff I trend do it more in .Net using my own assemblies but for Tech anim stuff since its always the same the .Net max script combo save a lot of work :slight_smile:
Best,

Hey, sorry to dig up an old thread, but my question is pretty relevant to this stuff…

I’ve started implementing SVN integration into 3dsmax using SharpSvn through dotNet, it was really easy to get the basic stuff working, but now I’ve hit a roadblock.

Basically I need to create a Collection of class SvnLogEventArgs (which is a SharpSvn class), and I can’t figure it out.

Making a Collection of String objects is easy since it’s a System thing (as in Biddle’s great example):


local aqn = ( dotNet.getType "System.String" ).AssemblyQualifiedName
local logItems = dotNetObject ("System.Collections.ObjectModel.Collection`1[[" + aqn + "]]")

This works fine.

But then I try to make a Collection using the SharpSvn class, like so:


local aqn = ( dotNet.getType "SharpSvn.SvnLogEventArgs" ).AssemblyQualifiedName
local logItems = dotNetObject ("System.Collections.ObjectModel.Collection`1[[" + aqn + "]]")

And it ends up spitting the error:
– Runtime error: Cannot resolve type: System.Collections.ObjectModel.Collection`1[[SharpSvn.SvnLogEventArgs, SharpSvn, Version=1.6016.1637.10768, Culture=neutral, PublicKeyToken=d729672594885a28]]

I’m guessing that’s because I’ve only defined “SharpSvn” from within Maxscript by using LoadAssembly pointing at the SharpSvn.dll directly, and so the dotNet method it uses to construct the Collection has no concept of where this class is coming from (since it’s not a default Windows DLL).

Am I on the right track there? Is there any way to make this work from within Maxscript or am I out of luck?

Can anyone suggest a better route?

Make a helper function in pure .NET to create it and call it from MXS:

class SharpSvnHelpers
{
    public static Collection<SvnLogEventArgs> CreateCollection()
    {
        return new Collection<SvnLogEventArgs>();
    }
}

In max:

logItems = (dotNetClass "MyAssembly.SharpSvnHelpers").CreateCollection()

Or actually you could probably generalize this and have .NET create any generic collection through reflection and you can pass the type of collection and generic items as Type objects or strings.

Hey Guys,
The problem still exists with me… I am always getting 0 when i try to get the logs. Can any one help me? MoP, Did u find any solution? the code:



sharpSvnPath =  local Path, -- Change it to where ever the sharpSvn dll is
	dll = dotNet.loadAssembly(sharpSvnPath+"SharpSvn.dll"),
	mainClass = "SharpSvn",
	client = dotnetObject (dotnetclass (mainClass + ".svnClient")),

fn fetchLogs = 
(
	local logArgs =  dotnetObject(dotNetClass(mainClass+".SvnInfoArgs"))
	local logEvntArgs = ( dotNet.getType (mainClass+".SvnInfoEventArgs") ).AssemblyQualifiedName
-- 		local logItems = dotnetObject ("System.Collections.ObjectModel.collection`1[["+logEvntArgs+"]]")
	logItems = dotNetObject ("System.Collections.Generic.List`1[["+logEvntArgs+"]]")
-- 		local logItems2 = dotnetObject ("System.Collections.arrayList")
	local uri =  (dotnetclass (mainClass + ".SvnTarget")).Fromstring(repoPath)		
				
	client.getInfo uri logArgs logItems
	
	print (logItems.Revision)
)