Clearscript: InvalidOperationException when adding Microsoft.VisualBasic.dll and Microsoft.VisualBasic.Core.dll from .NET Core

Created on 3 Dec 2020  路  5Comments  路  Source: microsoft/ClearScript

When using ClearScript 7.0 under .NET 5.0, I get System.InvalidOperationException: 'Sequence contains more than one matching element' in the following code:

var c = new HostTypeCollection();
c.AddAssembly(Assembly.LoadFile(@"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.0\Microsoft.VisualBasic.dll"));
c.AddAssembly(Assembly.LoadFile(@"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.0\Microsoft.VisualBasic.Core.dll"));
engine.AddHostObject("xx", c);

I have a suspicion this might be related to type forwarding in these two assemblies.
Could you please point me to a fix/workaround for this?

enhancement fixed question

All 5 comments

Hi @yevgeni-zolotko,

This is an odd case where two types appear to be identical but fail the equality test. Since a ClearScript type collection is essentially a full-name-to-type dictionary, it can't hold both types.

You can resolve this issue by excluding one or both types via a custom filter. Here's a sample method that creates a generic deduplication filter:

``` C#
private static Predicate MakeFilter(HostTypeCollection collection) {
return type => {
var segments = type.FullName.Split('.');
var nameSpace = string.Join(".", segments.Take(segments.Length - 1));
var node = string.IsNullOrWhiteSpace(nameSpace) ? collection : collection.GetNamespaceNode(nameSpace);
return !(node?.ContainsKey(segments[segments.Length - 1]) ?? false);
};
}


In your example, you might use it like this:

``` C#
var c = new HostTypeCollection();
c.AddAssembly(Assembly.LoadFile(path1));
c.AddAssembly(Assembly.LoadFile(path2), MakeFilter(c));

Good luck!

@ClearScriptLib thank you very much for your reply!
That helped for the most of cases, but the following still produces an InvalidOperationException (see the particular file names):

var c = new HostTypeCollection();
.AddAssembly(Assembly.LoadFile(@"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.0\System.Data.Common.dll"), MakeFilter(c));
c.AddAssembly(Assembly.LoadFile(@"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.0\System.Data.DataSetExtensions.dll"), MakeFilter(c));
engine.AddHostObject("xx", c);

The type in question seems to be System.Data.DataRowComparer`1. The filter code does not find the type name with the backtick in the property bag. Is there a way around this?

Hi @yevgeni-zolotko,

Oops, forgot about the backtick encoding for generic types. This filter should work better:

C# private static Predicate<Type> MakeFilter(HostTypeCollection collection) { return type => { var name = type.FullName; var index = name.LastIndexOf('`'); if (index >= 0) { name = name.Substring(0, index); } var ns = string.Empty; index = name.LastIndexOf('.'); if (index >= 0) { ns = name.Substring(0, index); name = name.Substring(index + 1); } var node = string.IsNullOrWhiteSpace(ns) ? collection : collection.GetNamespaceNode(ns); return !(node?.ContainsKey(name) ?? false); }; }

Sorry about this inconvenience. The HostTypeCollection code is some of the oldest in ClearScript, far predating .NET Core and type forwarding. It might make sense to change the way it compares types. We'll take a closer look for the next release.

Thanks!

Thank you very much, this works.

We've posted ClearScript 7.1.

Was this page helpful?
0 / 5 - 0 ratings