Posts: 65
Threads: 32
Joined: Jan 2013
Hi -
I'm not understanding the syntax in the CsScript example - user interface:
Macro CsScript example - use interface
interface# IFast :IDispatch
,#Add(a b)
,[p]Prop(x)
,[g]#Prop
,#Overload(x)
,#Overload_2(BSTR's)
,{C7D9B459-0108-4F4A-9483-A7F60F18AF0A}
I'm guessing that # means number, [p] is put, and [g] is get? What I want to do is return a more complex data structure - something like this:
Function ParseJson
[DataContract]
public class Results
{
;;;;[DataMember]
;;;;public List<BodyField> bodyItems { get; set; }
;;;;[DataMember]
;;;;public ImpressionItems impressionItems { get; set; }
;;;;[DataMember]
;;;;public RecommendationItems recommendationItems { get; set; }
}
where the elements of the returned object were themselves objects. The objects are composed of List<> and collections of strings. They are [DataContract]/[DataMembers] because they are used by DataContractJsonSerializer to map JSON to C# objects.
Do I have to define a GUID for each class type?
Thanks
Sean
Posts: 12,092
Threads: 142
Joined: Dec 2002
Quote:I'm guessing that # means number, [p] is put, and [g] is get?
Yes, # is int, [g] and [p] are used for properties.
Quote:What I want to do is return a more complex data structure
With many class objects can be used IDispatch.
However cannot return generic types, like List<>. More info: http://msdn.microsoft.com/en-us/library ... 80%29.aspx . Convert List<> to array.
Works with non-generic collections.
Macro test CScript - get collection
out
CsScript x.AddCode("")
IDispatch t=x.CreateObject("Test")
;IDispatch k=t.k ;;error
ARRAY(str) b=t.GetListAsArray ;;OK
for(_i 0 b.len) out b[_i]
IDispatch a=t.a ;;OK
out a.Count
out a.Item(0)
a.Item(0)="newstring"
#ret
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
public class Test
{
public List<string> k { get; private set;}
public ArrayList a { get; private set;}
public Test()
{
k=new List<string>(); k.Add("string in List");
a=new ArrayList(); a.Add("string in ArrayList");
}
public string[] GetListAsArray() { return k.ToArray(); }
}
Here used string[] in C#, and ARRAY(str) in QM. In your case will be BodyField[] and ARRAY(IDispatch).
Posts: 65
Threads: 32
Joined: Jan 2013
Great - that works :-).
What if I wanted to return an array of a type that wasn't string?
public class QMBodyField
{
public string fieldName { get; set; }
public string defaultText { get; set; }
public string text { get; set; }
}
public class QMResults
{
public QMBodyField[] bodyItems { get; set; }
public string impressionFieldName { get; set; }
public string[] recommendationItems { get; set; }
}
This will work fine for an array of strings:
ARRAY(str) recommendationItems = results.recommendationItems
out F"n recommendationItems = {recommendationItems.len}"
for(_i 0 recommendationItems.len)
,out F"{_i} {recommendationItems[_i]}"
but I don't see how to index into the elements of bodyItems (something like bodyItems [0].fieldname?)
Posts: 12,092
Threads: 142
Joined: Dec 2002
ARRAY(IDispatch) a=results.bodyItems
for _i 0 a.len
,out a[_i].fieldName
Posts: 65
Threads: 32
Joined: Jan 2013
Hm. This worked in your example but not my code. I think I've found out what the issue is (so my problem is solved) but I don't understand why this makes a difference. First - a working example:
Function [b]CSTest[/b] [help1][/help1]
[code]
out
CsScript x.AddCode("")
IDispatch t=x.CreateObject("Test")
;IDispatch k=t.k ;;error
ARRAY(str) b=t.GetListAsArray ;;OK
for(_i 0 b.len) out b[_i]
IDispatch a=t.a ;;OK
out a.Count
out a.Item(0)
a.Item(0)="newstring"
ARRAY(IDispatch) testStrings = t.testStrings
out F"Length of testStrings array {testStrings.len}"
for _i 0 testStrings.len
,out testStrings[_i].aString
,out testStrings[_i].bString
#ret
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
public class Test2Strings{
,public string aString {get;set;}
,public string bString;
}
public class Test
{
public List<string> k { get; private set;}
public ArrayList a { get; private set;}
public Test2Strings[] testStrings ;//{get; set;}
public Test()
{
k=new List<string>(); k.Add("string in List");
a=new ArrayList(); a.Add("string in ArrayList");
testStrings = new Test2Strings[3];
for (int i=0;i<testStrings.Length; i++){
,testStrings[i] = new Test2Strings();
,testStrings[i].aString = "First String " + i;
,testStrings[i].bString = "Second String " + i;
,}
}
public string[] GetListAsArray() { return k.ToArray(); }
}
[/code]
When I run this I get the output
string in List
1
string in ArrayList
Length of testStrings array 3
First String 0
Second String 0
First String 1
Second String 1
First String 2
Second String 2
but if I change
public Test2Strings[] testStrings ;//{get; set;}
to
public Test2Strings[] testStrings {get; set;}
the output is
string in List
1
string in ArrayList
Error (RT) in CSTest: type mismatch. ?
This must mean that adding the accessors is fine for simple C# strings and for string[]s - but if there is a IDispatch-ish type that the accessors add some type information that then throws the mismatch. No idea what this is but I can go forward from here now. Thanks!
Posts: 12,092
Threads: 142
Joined: Dec 2002
Macro Macro2136
out
CsScript x.AddCode("")
IDispatch t=x.CreateObject("Test")
;VARIANT v=t.testStrings; out "0x%X" v.vt ;;should be 0x2009 (VT_DISPATCH|VT_ARRAY), but with {get; set;} it is 0x200D (VT_UNKNOWN|VT_ARRAY), don't know why
;assign to ARRAY(IUnknown) and convert elements to IDispatch. QM does not do it automatically.
ARRAY(IUnknown) _testStrings = t.testStrings
ARRAY(IDispatch) testStrings.create(_testStrings.len)
for(_i 0 testStrings.len) testStrings[_i] = _testStrings[_i]
_testStrings=0
out F"Length of testStrings array {testStrings.len}"
for _i 0 testStrings.len
,out testStrings[_i].aString
,out testStrings[_i].bString
#ret
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
public class Test2Strings{
,public string aString {get;set;}
,public string bString;
}
public class Test
{
public Test2Strings[] testStrings {get; set;}
//public Test2Strings[] testStrings;
public Test()
{
testStrings = new Test2Strings[3];
for (int i=0;i<testStrings.Length; i++){
,testStrings[i] = new Test2Strings();
,testStrings[i].aString = "First String " + i;
,testStrings[i].bString = "Second String " + i;
,}
}
}
Posts: 12,092
Threads: 142
Joined: Dec 2002
Or use MarshalAs.
Macro Macro2139
out
CsScript x.AddCode("")
IDispatch t=x.CreateObject("Test")
;VARIANT v=t.testStrings; out "0x%X" v.vt ;;correct, 0x2009
ARRAY(IDispatch) testStrings = t.testStrings
out F"Length of testStrings array {testStrings.len}"
for _i 0 testStrings.len
,out testStrings[_i].aString
,out testStrings[_i].bString
#ret
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
public class Test2Strings{
,public string aString {get;set;}
,public string bString;
}
public class Test
{
public Test2Strings[] testStrings {[return:MarshalAs(UnmanagedType.IDispatch)] get; set;}
//public Test2Strings[] testStrings;
public Test()
{
testStrings = new Test2Strings[3];
for (int i=0;i<testStrings.Length; i++){
,testStrings[i] = new Test2Strings();
,testStrings[i].aString = "First String " + i;
,testStrings[i].bString = "Second String " + i;
,}
}
}
Posts: 65
Threads: 32
Joined: Jan 2013
Very cool and very helpful. Thanks!
|