cancel
Showing results for 
Search instead for 
Did you mean: 

using System.XML.Linq in unity WF Script

Srinivas_Kaira1
Champ on-the-rise
Champ on-the-rise

Hi,

I am running into below issue. I am working on a Unity WF Script and I have added V4.0 System.Core also. I am getting below error.

The type or namespace name 'Linq' does not exist in the namespace 'System.Xml' (are you missing an a
ssembly reference?)

Any idea how can I solve this error?

Thanks for the help.

Regards

Srinivas

1 ACCEPTED ANSWER

Scott_McLean
Elite Collaborator
Elite Collaborator

Hi Srivinas,

This is an issue in versions earlier than 16. Linq includes static references that are incompatible with the Unity script environment.

Options to fix the problem are:

1. Upgrade to v16, where Linq is supported

2. Convert to a loop or other object that doesnot use Linq

Hope that helps,

-Scott

View answer in original post

15 REPLIES 15

Scott, I don't think what you said is necessarily accurate.

This Unity API blog post talks about what changed in 16:

www.onbase.com/.../linq-in-unity-scripts

It is entirely possible to use LINQ in many ways in earlier versions of OnBase- though for some uses it will be inconvenient. The Unity Script compiler in earlier versions won't let you do things that get compiled as a static anonymous method delegate, and the compiler will tell you something pretty specific (though not necessarily helpful if you don't already know what the problem is).

You can still use a lot of LINQ's power, and you can get around that specific problem by declaring a delegate method in your code instead of using an anonymous function- just at a large expense in brevity in the code.

 

EDIT: nobody should rely on my exactwording (or even understanding!) of the details too much.  E.g. I think "static anonymous method delegate" gets the point across but may not be absolutely precise terminology.

I'd be mighty interested to see an example where this worked in an earlier version, as our experience has been that anything containing a lambda operator (including Linq expressions) resulted in an error in earlier version Unity scripts.

Scott, I marked your answer as correct as this is not supported until OnBase 16. There are ways around using LINQ (the same cannot be said to LINQ to XML as in this case). You can add a reference to System.LINQ and System.Core and using some code like this I wrote in OnBase 13.

string invContact = "inv contact";
string poContact = "po contact";
string nwcmContact = "nwcm contact";
string socContact = "soc contact";

//list that will hold the results from our search
List results = keywordRecordList.FindAll(
kr => kr.KeywordRecordType.Name.ToLower().Contains(invContact) ||
kr.KeywordRecordType.Name.ToLower().Contains(poContact) ||
kr.KeywordRecordType.Name.ToLower().Contains(nwcmContact) ||
kr.KeywordRecordType.Name.ToLower().Contains(socContact)).Take(6).ToList();

I had to create the string fields first as the issue with static fields would come into play if I just passed the string into the Lambda Expression. LINQ syntax will not work at all. There is no work around for that until OnBase 16.

Scott, below are some examples of how you can use LINQ (but it may be more cumbersome than it is worth).

After thinking a little more (mostly about the fact that I don't really know LINQ-To-XML!), you're probably right that Srinivas won't be successful- but his initial compiler error message isn't about the LINQ limitations in Unity Scripts pre-16.

The code below compiles (I threw it in a Global Client Script) on OnBase v15, referencing the System.Core 4.0.0 Assembly and "using System.Collections.Generic", "using System.Linq;".



public void OnGlobalClientScriptExecute(Hyland.Unity.Application app, Hyland.Unity.GlobalClientEventArgs args)
{

//
//String examples of LINQ Where
//
List strings = new List {"ab","bc","cd"};
IEnumerable subset;
IEnumerable upperStrings;

//this won't compile
//error: Unity Event implementations cannot contain static fields: "yyAFLINQTestGood.CS$<>9__CachedAnonymousMethodDelegate6".
//subset = strings.Where(x => x == "ab");

//this won't compile either
//subset = strings.Where(delegate(string s) {return s == "bc";});

//or this
//Func StartsWithC = delegate(string s) {return s.StartsWith("c");};
//subset = strings.Where(StartsWithC);

//or this
//upperStrings = strings.Select(x => x.ToUpper());

//these lambdas will all work
//see methods defined below
subset = strings.Where(x => StartsWithA(x));
subset = strings.Where(x => StartsWith(x, "a"));
subset = strings.Where(x => AreEqual(x,"ab"));

upperStrings = strings.Select (x => MyUpper(x));

//or syntax where we pass a method that meets an expected Func<> signature instead of a lambda

//simpler or more confusing? depends on what you're used to
subset = strings.Where(StartsWithA);
upperStrings = strings.Select(MyUpper);

//
//Examples of other LINQ functions
//LINQ is not just Where!
//Some don't require any special tricks
//some will require adjustments like Where did
//

List numbers = new List {1,2,2,3,4,5};

long max = numbers.Max();
long sum = numbers.Sum();
double average = numbers.Average();
long product = numbers.Aggregate(1L, MyProduct);

IEnumerable distinctNumbers = numbers.Distinct();


}

bool StartsWithA(string s) { return s.StartsWith("A"); }

bool StartsWith(string s, string start) { return s.StartsWith(start); }

bool AreEqual(string a, string b) { return a == b; }

string MyUpper(string s) { return s.ToUpper(); }

long MyProduct(long runningValue, long newInput) { return runningValue * newInput; }

Srinivas, I poked around a little more and at least some LINQ-To-XML functionality definitely can be used in a Unity Script with the techniques I described above. This is a bit more cumbersome than LINQ usage often is, so your plan of moving code to a DLL that gets imported may be best for you.

My proof-of-concept adds references to (I'm not sure these are all actually required):


System.Core
System.Xml
System.Xml.Linq



And using statements (again, not sure these are all required):


using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

And code:



public void OnSomeKindOfUnityScript(Hyland.Unity.Application app, Hyland.Unity.SomeKindOfEventArgs args)
{
XDocument myDocument = GetWhatever();

//won't compile
//var subsetOfElements - elements.Where(x => (string)x.Attribute("name") == "Bob");

//will compile
var subsetOfElements = elements.Where(x => AttributeEquals(x.Attribute("name"), "Bob");
}

bool AttributeEquals(XAttribute attribute, string s) {return (string)attribute == s;}

XDocument GetWhatever()
{
//...
}



Depending on your needs, you might end up writing a LOT of helper methods like AttributeEquals(), maybe with different overloads.

You could also rewrite that helper as "bool AttributeEquals(XElement element, string attrName, string s)" or some other form that you find most convenient.

 

Again, moving your code to a DLL for the simplest LINQ usage might still be the most convenient option, but it seems like it is entirely possible to use LINQ-To-XML in pre-16 Unity Scripts with a little extra overhead.