传递IEnumerable的变量到.NET从ColdFusion的变量、IEnumerable、ColdFusion、NET

2023-09-04 08:53:58 作者:心野路子宽,

我正在做一些ColdFusion的10集成了一个自定义.NET的DLL,我没有调整的能力。在这个过程中,我已经能够做到这一点,我需要做的比创建一个其他一切的IEnumerable 数据类型传递到的对象的方法之一。这是我需要整合:

I'm working on doing some ColdFusion 10 integration with a custom .NET DLL that I don't have the ability to tweak. During this process, I've been able to do everything that I need to do other than create an IEnumerable data type to pass to one of the methods of the object. Here's what I need to integration with:

这是 Set_Events 方法我在遇到麻烦。我可以创建一个被认为是该枚举变量的一部分的个别事件,但我不能创造什么它显然是希望为正确的变量类型。我试着这样做:

It's the Set_Events method that I'm having the trouble with. I can create the individual Events that are supposed to be part of that enum variable, but I'm unable to create what it apparently is expecting as the proper variable type. I've tried doing this:

<cfset enum = createObject(".net", "System.Collections.Generic.IEnumerable__1") />

和这给了我一个有效的.NET对象,用的GetEnumerator()方法:

And this gives me a valid .NET object, with a GetEnumerator() method:

当我试图调用该方法:

<cfdump var="#enum.GetEnumerator()#">

这只是给了我以下错误:

That just gives me the following error:

The GetEnumerator method was not found.

其他的事情我已经试过:

创建一个泛型列表和添加的东西:

<cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", "dotNetCoreProxy.jar") />
<cfset eventList.Add(javacast("bigdecimal", "30.1234" )) />

这使我有以下错误:

An exception occurred while instantiating a Java object. The class must not be an interface or an abstract class. If the class has a constructor that accepts an argument, you must call the constructor explicitly using the init(args) method. Error : System.Collections.Generic.List__1

这再次给了我同样的错误:

And this gives me the same error again:

<cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", "dotNetCoreProxy.jar") />
<cfset eventList.Add("foo") />

尝试初始化列表

这是利这code工作:

Trying to Init the List

This code from Leigh works:

<cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", "dotNetCoreProxy.jar") />
<cfset elemClass = createObject(".net", "System.String", "dotNetCoreProxy.jar") />
<cfset elemType = elemClass.getDotNetClass() />
<cfset eventList.init( elemType ) />
<cfset eventList.Add("foo") />
<cfdump var="#eventList#">

但这并不:

<cfobject type="dotnet" name="VideoWallEvent" class="Utilities.VideoWall.VideoWallEvent" assembly="#ExpandPath("Utilities.dll")#">
<cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", "dotNetCoreProxy.jar") />
<cfset elemType = VideoWallEvent.getDotNetClass() />
<cfset eventList.init( elemType ) />
<cfdump var="#eventList#">

我收到以下错误:

I get the following error:

Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( System.RuntimeType ).

JNBProxyGUI.exe

传智播客C 基础课件 .Net文档类资源 CSDN下载

本已经完全无用。我可以浏览到我的Utilities.dll文件,并装配从GAC添加System.Collections中,但在项目菜单生成选项始终是禁用的,并且没有显示任何一旦这些组件已被添加窗格的。

JNBProxyGUI.exe

This has been completely useless. I can browse to my Utilities.dll file, and add the System.Collections assembly from GAC, but the Build option in the Project menu is always disabled, and nothing shows in any of the panes once those assemblies have been added.

我在一个页面上运行所有的下列code:

I've run all of the following code on one page:

<cfset UtilitiesProxy = ExpandPath("UtilitiesProxy.jar") />
<cfset DotNetCoreProxy = "dotNetCoreProxy.jar" />
<cfset CoStarUtilities = ExpandPath("CoStar.Utilities.dll") />

<h2>Try using base DLLs and DotNetCore</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#CoStarUtilities#">
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", DotNetCoreProxy) />
    <cfdump var="#eventList.init(VideoWallEvent.getDotNetClass())#"> (error line)
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

<h2>Try using the Utilities Proxy for Everything</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#UtilitiesProxy#">
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", UtilitiesProxy) /> (error line)
    <cfdump var="#eventList.init(VideoWallEvent.getDotNetClass())#">
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

<h2>Try using Utilities Proxy for VideoWall, and DotNetCore for List</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#UtilitiesProxy#">
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", DotNetCoreProxy) />
    <cfdump var="#eventList.init(VideoWallEvent.getDotNetClass())#"> (error line)
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

<h2>Try Initing Wall Event</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#CoStarUtilities#">
    <cfset VideoWallEvent.Init() />
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", DotNetCoreProxy) />
    <cfdump var="#eventList.init(VideoWallEvent.getDotNetClass())#"> (error line)
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

<h2>Try Initing Wall Event</h2>
<cftry>
    <cfobject type="dotnet" name="VideoWallEvent" class="CoStar.Utilities.VideoWall.VideoWallEvent" assembly="#CoStarUtilities#">
    <cfset VideoWallEvent.Init() />
    <cfset eventList = CreateObject(".net","System.Collections.Generic.List`1", DotNetCoreProxy) />
    <cfdump var="#eventList.init(VideoWallEvent)#"> (error line)
    <cfcatch>
        <h3><cfoutput>#cfcatch.type#</cfoutput></h3>
        <p><cfoutput>#cfcatch.message#: #cfcatch.detail#</cfoutput></p>
    </cfcatch>
</cftry>

和我碰到下面的错误输出(提示,其中每一个出现故障)。

And I get the following error output (hint, every single one of these fails).

09:22:45.045 - Object Exception - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 9
    Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( System.RuntimeType ).

09:22:48.048 - coldfusion.runtime.dotnet.ProxyGenerationException - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 19
09:22:48.048 - Object Exception - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 31
    Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( System.RuntimeType ).

09:22:48.048 - Object Exception - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 43
    Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( System.RuntimeType ).

09:22:48.048 - Object Exception - in C:/inetpub/LandsofAmerica/scribble/VideoWall/index.cfm : line 55
    Unable to find a constructor for class System.Collections.Generic.List__1 that accepts parameters of type ( CoStar.Utilities.VideoWall.VideoWallEvent ).

我已经生成了(我认为是)所有我需要的物品的代理。

I've generated a proxy with (what I think is) all of the items that I need.

所以,现在我卡住了。我可以实例,并填写所有必需的对象,使这个东西的工作,我只是不能所有的物体推到一起,使他们的工作。什么想创建必要的枚举对象,以填补S​​et_Events方法时想什么?

So now I'm stuck. I can instantiate and fill all of the necessary objects to make this thing work, I just can't push all of the objects together to make them work. What am I missing when trying to create the ENum object necessary to fill the Set_Events method?

推荐答案

如前所述,您需要使用一个具体的类(而不是接口)。然而,看着方法签名,它必须是一个实现的 System.Collections中。通用 .IEnumerable ,而不是的 System.Collections.IEnumerable 。只有后者对于非泛型集合。泛型集合,你可以使用的一个例子是 名单,其中,T&GT; ,其中&LT; T&GT; 的对象列表包含的类型。 (您需要查看您的API来确定物体的类型)。

As mentioned, you need to use a concrete class (not the interface). However, looking at the method signature, it must be one that implements System.Collections.Generic.IEnumerable, and not System.Collections.IEnumerable. The latter is only for non-generic collections. One example of a generic collection you could use is List<T>, where <T> is the type of object the list holds. (You will need to review your API to determine the object type).

不幸的是...有一个的问题泛型类的。基本上使用的CreateObject 的工具无法生成代理仿制药。 (本博客文章说,在CF9得到解决,但在我的测试中,我用9.0.1遇到同样的问题 - 情况因人而异),因此你需要用你自己做的 JNBProxyGUI.exe 。坦率地说这是不是最直观的工具..但有点争吵后,我设法得到它CF9下工作。幸运的是这只是一个时间的事件。

Unfortunately ... there is an issue with Generic classes. Essentially the tool used by createObject cannot generate proxies for Generics. (The blog entry says it was resolved in CF9, but in my tests I encountered the same problem with 9.0.1 - YMMV.) So you need to do it yourself using the JNBProxyGUI.exe. Frankly it is not the most intuitive tool .. but after a little wrangling I managed to get it working under CF9. Fortunately it is only a one time event.

导出生成的代理JAR文件后,使用在博客条目中的例子来创建一个通用的列表。就在代理jar添加到汇编列表。说集合存储简单的字符串:

After exporting the generated proxies to a jar file, use the example in the blog entry to create a generic List. Just add the proxy jar to the assembly list. Say the Collection stores simple Strings:

    // create a generic list of strings ie new List<String>()
    path = "c:/path/yourGenericsProxy.jar,c:/path/yourApplication.dll"; 
    list = createObject(".net", "System.Collections.Generic.List__1", path);
    elemClass = createObject(".net", "System.String", path);
    elemType = elemClass.getDotNetClass();
    list.init( elemType );

一旦列表被初始化,您可以添加一些元素是:

Once the List is initialized, you can add a few elements to it:

    list.add( "foo" );
    list.add( "bar" );

然后最后调用的GetEnumerator(),并将其传递到方法然后通过列表到你的方法:

Then finally invoke GetEnumerator() and pass it into your method Then pass the List into your method:

    // wrong: yourObject.Set_Events( list );
    yourObject.Set_Events( list );

(如果您对生成的代理有任何问题,只是问。)

(If you have any questions about generating the proxies, just ask.)

更新:

正如丹指出,他的方法是使用的IEnumerable 的没有的IEnumerator的。因此,列表本身应该被传递到 set_Event ,不是 Get_Enumerator()(如在previous例子)。此外,当你调用的CreateObject ,的assemblyList必须包括代理jar和DLL文件。否则,方法调用(S)可能会失败。原来那是后来的问题的原因。

As Dan pointed out, his method is using IEnumerable not IEnumerator. So the List itself should be passed into set_Event, not Get_Enumerator() (as in the previous example). Also, when you invoke createObject, the assemblyList MUST include both the proxy jar AND the dll file. Otherwise the method call(s) may fail. Turns out that was the cause of the later problems.

下面是与CF10工作修正版本。

Below is a corrected version that works with CF10.

再生代理jar

开启JNBProxyGUI.exe,选择创建新的Java - &GT; .NET项目 输入本地Java设置(我的设置) 在远程主机/端口:本地主机6089 Java的路径:C:\ ColdFusion10 \ cfusion \码头\ JRE \ BIN \的java.exe jnbcore.jar:C:\ ColdFusion10 \ cfusion \ lib目录\ jnbcore.jar bcel.jar:C:\ ColdFusion10 \ cfusion \ LIB \ becel-5.1-jnbridge.jar Open JNBProxyGUI.exe and select Create new Java -> .NET Project Enter local java settings (My settings) Remote host/port: local host 6089 Java path: C:\ColdFusion10\cfusion\jetty\jre\bin\java.exe jnbcore.jar: C:\ColdFusion10\cfusion\lib\jnbcore.jar bcel.jar: C:\ColdFusion10\cfusion\lib\becel-5.1-jnbridge.jar

清理:

为了安全起见,我停止了CF和移出所有生成的代理罐子WEB-INF \ cfclasses \ dotNetProxy 除了 dotNetCoreProxy.jar。然后,重新启动CF和运行code。它完美地工作。串。 (查看完整的code以下)。

Just to be safe, I stopped CF and removed all generated proxy jars from WEB-INF\cfclasses\dotNetProxy except dotNetCoreProxy.jar. Then restarted CF and ran the code. It worked perfectly. String. (See complete code below).

MyClass.cs

using System;
using System.Text;
using System.Collections.Generic;

namespace MyLibrary
{
    public class MyClass {
        private IEnumerable<CustomClass> events;

        public void set_Events(IEnumerable<CustomClass> evts) 
        {
            this.events = evts;
        }

        public IEnumerable<CustomClass> get_Events()
        {
            return this.events;
        }
    }
}

CustomClass.cs

using System;
using System.Text;
using System.Collections.Generic;

namespace MyLibrary
{
    public class CustomClass
    {
        private string title;
        public CustomClass(string title)
        {
            this.title = title;
        }

        public string getTitle()
        {
            return this.title;
        }

        public override string ToString()
        {
            return getTitle();
        }
    }
}

CF code:

<cfscript>
    // MUST include both proxy jar and DLL file
    path = arrayToList([ExpandPath("./MyLibrary.dll"), ExpandPath("genericListAndEnumerator.jar")]);
    //initialize custom class
    customObj = createObject(".net", "MyLibrary.CustomClass", path).init("Blah, blah");
    elemType = customObj.getDotNetClass();

    // create generic list of custom class
    list = CreateObject(".net","System.Collections.Generic.List__1", path);
    list.init( elemType );
    list.add( customObj );

    // test setter
    mainObj = createObject(".net", "MyLibrary.MyClass", path);
    mainObj.set_Events( list );

    // test getter
    enum = mainObj.get_Events().getEnumerator();
    writeDump(enum);
    while (enum.MoveNext()) {
        WriteDump("Current="& enum.Get_Current().toString());
    }
</cfscript>