6

カスタム .NET DLL との ColdFusion 10 の統合に取り組んでいますが、微調整することはできません。IEnumerableこのプロセス中に、オブジェクトのメソッドの 1 つに渡すデータ型を作成する以外に、必要なすべてのことを行うことができました。統合する必要があるのは次のとおりです。

ここに画像の説明を入力

Set_Events私が悩んでいる方法です。その列挙型変数の一部であるはずの個々のイベントを作成できますが、適切な変数型として期待されているように見えるものを作成できません。私はこれをやってみました:

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

これにより、有効な .NET オブジェクトとGetEnumerator()メソッドが得られます。

ここに画像の説明を入力

そのメソッドを呼び出そうとすると:

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

次のエラーが表示されます。

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

そして、これは私に同じエラーを再び与えます:

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

リストを初期化しようとしています

Leigh のこのコードは次のように機能します。

<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#">

次のエラーが表示されます。

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

JNBProxyGUI.exe

これは完全に無駄になりました。Utilities.dll ファイルを参照し、GAC から System.Collections アセンブリを追加できますが、[プロジェクト] メニューの [ビルド] オプションは常に無効になっており、これらのアセンブリが追加されると、どのペインにも何も表示されません。

試験方法

次のすべてのコードを 1 つのページで実行しました。

<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>

そして、次のエラー出力が表示されます (ヒント、これらのすべてが失敗します)。

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 ).

必要なすべてのアイテムを含むプロキシを生成しました (と思います)。

JNBProxyGUI

結論

だから今私は立ち往生しています。これを機能させるために必要なすべてのオブジェクトをインスタンス化して埋めることはできますが、すべてのオブジェクトをまとめて機能させることはできません。Set_Events メソッドを満たすために必要な ENum オブジェクトを作成しようとすると、何が欠けていますか?

4

2 に答える 2

7

前述のように、(インターフェイスではなく) 具体的なクラスを使用する必要があります。ただし、メソッド シグネチャを見ると、System.Collections を実装するものである必要があります。ジェネリック.IEnumerableであり、 System.Collections.IEnumerableではありません。後者は、非ジェネリック コレクション専用です。使用できる一般的なコレクションの一例は ですList<T>。ここ<T>で、 はリストが保持するオブジェクトのタイプです。(オブジェクト タイプを決定するには、API を確認する必要があります)。

残念ながら、ジェネリック クラスには問題があります。基本的に、 で使用されるツールcreateObjectはジェネリックのプロキシを生成できません。(ブログ エントリには、CF9 で解決されたと書かれていますが、私のテストでは、9.0.1 - YMMV で同じ問題が発生しました。) したがって、JNBProxyGUI.exeを使用して自分で行う必要があります。率直に言って、それは最も直感的なツールではありません..しかし、少し苦労した後、CF9で動作させることができました。幸いなことに、これは 1 回限りのイベントです。

生成されたプロキシを jar ファイルにエクスポートした後、ブログ エントリの例を使用して汎用のList. プロキシ jar をアセンブリ リストに追加するだけです。Collection に単純なStringが格納されているとします。

    // 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 );

が初期化されたらList、いくつかの要素を追加できます。

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

次に、最後に GetEnumerator() を呼び出してメソッドに渡します。次に、Listをメソッドに渡します。

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

(プロキシの生成について質問がある場合は、質問してください。)


アップデート:

Dan が指摘したように、彼の方法はIEnumeratorを使用してIEnumerable いません。そのため、(前の例のように)ではなく、Listそれ自体を に渡す必要があります。また、呼び出すときは、assemblyList にプロキシ jar と dll ファイルの両方を含める必要があります。そうしないと、メソッド呼び出しが失敗する可能性があります。それがその後の問題の原因であることが判明しました。set_EventGet_Enumerator()createObject

以下はCF10で動作する修正版です。

プロキシ jar を再生成しました

  1. JNBProxyGUI.exe を開き、選択します。Create new Java -> .NET Project
  2. ローカル Java 設定を入力 (マイ設定)
    • リモート ホスト/ポート: ローカル ホスト 6089
    • Java パス: 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
  3. をクリックしProject > Edit Assembly List > Addます。「mscorlib.dll」を見つけて選択します
  4. をクリックしProject > Add Classes from Assembly Fileます。「mscorlib.dll」を見つけて選択します (その後、GUI によってクラスのリストが生成されます。時間がかかる場合があります)。
  5. 「環境」リストでSystem.Collections.Genericパッケージを選択し、 をクリックしますAdd
  6. 選択するEdit > Check All in Exposed Proxies
  7. Project > Build新しいプロキシ jar のパスとファイル名を選択して選択します。

掃除:

念のため、CF を停止し、生成されたすべてのプロキシ jarをdotNetCoreProxy.jarWEB-INF\cfclasses\dotNetProxy 以外から削除しました。その後、CF を再起動し、コードを実行しました。それは完璧に機能しました。弦。(以下の完全なコードを参照してください)。


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コード:

<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>
于 2013-05-25T07:21:39.127 に答える
1

問題は、インターフェイスのメソッドを呼び出そうとしていることです。代わりに、そのインターフェースを に渡すために、そのインターフェースを実装するクラスのインスタンスを作成する必要がありますSet_Events()。以下は、IEnumerable を実装する .NET クラスのリストです: IEnumerable Interface

于 2013-05-25T05:48:15.663 に答える