techbank.jp コミュニティ

     あれ?どうやるんだっけ?を解決する
ようこそ techbank.jp コミュニティ ログイン | ID登録 | ヘルプ
検索

自作アセンブリからのオブジェクト生成に失敗する

最終更新日 2009/7/9 20:55 by seiryu. 12 投稿.
Page 1 of 1 (13 items)
記事の並び替え: 前のトピック 次へ
  • 2009/6/23 23:06

    • seiryu
    • Top 25 Contributor
    • Joined on 2009/6/23
    • 訪問者級
    • ポイント 0

    自作アセンブリからのオブジェクト生成に失敗する

    はじめまして、seiryuと申します。
    PowerShellの勉強を始めて、1週間程度の初心者です。
    自作アセンブリからオブジェクト生成する処理の記述で、つまずいてしまいました。

    スクリプト例

    1   [void][System.Reflection.Assembly]::LoadFile("c:\common\MyLib.dll")
    2   $obj1 = New-Object MyLib.MyClass1
    3   $obj2 = New-Object MyLib.Etc.MyClass2

    1行目で自作アセンブリ(MyLib.dll)をロードします。MyLib.dllはC#で作成した.NETクラスライブラリです。
    MyLibにはnamespace "MyLib"にMyClass1があり、namespace "MyLib.Etc"にMyClass2があるとします。
    2行目でMyLib.MyClass1のオブジェクトを生成します。この処理は正常に行うことができます。
    3行目でMyLib.Etc.MyClass2のオブジェクトを生成しようとすると、以下のようなエラーが発生します。

    New-Object : Cannot find type [MyLib.Etc.MyClass2]: make sure the assembly containing this type is loaded.
    At line:1 char:18
    + $obj = New-Object <<<<  MyLib.Etc.MyClass
        + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
        + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

    どうも自作アセンブリで、既定のnamespace以外のnamespaceを設定している場合に、同様なエラーが発生するようなのですが、原因と回避方法がわかりません。
    ご存じの方いらっしゃいましたら、どうかご教授願います。

    • 投稿ポイント: 0
  • 2009/6/23 23:34 返信先

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    はじめまして HIROと申します。

    私の環境で試してみたのですが、とくにエラーにはなりませんでした。

    C#では下記のようなクラスを作成しました。(VS2008 .NET Framework3.5)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace MyLib
    {
        public class MyClass1
        {
            public void Test()
            {
                Console.WriteLine("HELLO TEST");
            }
        }
    }
    
    namespace MyLib.Etc
    {
        public class MyClass2
        {
            public void Test2()
            {
                Console.WriteLine("HELLO TEST2");
            }
        }
    }
    

    でseiryuさんのスクリプト例の通り行ったのですが、正常にオブジェクトの生成が行われました。

    PowerShellの実行環境はVer1.0です。

    もしよろしければ、自作アセンブリのソースを掲載して頂けませんか?

    よろしくお願いいたします。

    • 投稿ポイント: 0
  • 2009/6/24 0:33 返信先

    • seiryu
    • Top 25 Contributor
    • Joined on 2009/6/23
    • 訪問者級
    • ポイント 0

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    非常に早く反応していただき、感謝いたします。
    再確認したところ、エラー発生要因を思い違いしていたようです。
    掲載していたサンプルでは、確かにエラー発生しません。
    確認不足で安易に質問をしてしまい、まことに申し訳ありませんでした。

    実際にエラーが発生する条件は、次のような場合です。

    自作アセンブリ MyLib.dll

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using MyLib2;

    namespace MyLib
    {
        public class MyClass1
        {
            public void Test1()
            {
                Console.WriteLine("HELLO TEST1");
            }
        }
        public class MyClass2 : MyClass0
        {
            public void Test2()
            {
                Console.WriteLine("HELLO TEST2");
            }
        }
    }

    自作アセンブリ MyLib2.dll

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

    namespace MyLib2
    {
        public class MyClass0
        {
            public void Test0()
            {
                Console.WriteLine("HELLO TEST0");
            }
        }
    }

    PowerShellのスクリプト

    [System.Reflection.Assembly]::LoadFile("C:\data\MyLib.dll")
    [System.Reflection.Assembly]::LoadFile("C:\data\MyLib2.dll")
    $obj1 = New-Object MyLib.MyClass1   ← OK
    $obj2 = New-Object MyLib.MyClass2   ← エラー発生

    New-Object : Cannot find type [MyLib.MyClass2]: make sure the assembly containing this type is loaded.
    At line:1 char:19
    + $obj2 = New-Object <<<<  MyLib.MyClass2
        + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
        + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
     

    PowerShellはISE(CTP3)で確認しました。
    自作アセンブリが他の自作アセンブリを参照している場合に、単にLoadFileするだけでは不足しているのでしょうか。

    • 投稿ポイント: 0
  • 2009/6/24 10:29 返信先

    Re: 自作アセンブリからのオブジェクト生成に失敗する

     確かにエラーになりますね。

    おそらく参照設定にMyLib2を追加してMyLib.dllを作成しているかと思うのですが、そのMyLib2.dllがどこにあるのか探せないためエラーになるのでしょうね。

     単純に同一ディレクトリ内に配置しておけば問題なような気はするのですが、必ずしもそうではないようです。(参考 http://www.atmarkit.co.jp/fdotnet/technology/idnfw11_03/idnfw11_03_01.html)

    MyLib2がGACに登録されていればうまく通るような気がするのですがどうでしょうか?

    私自身、現段階ではどのようにしたらよいのかわかりません。

    わかり次第、レスしたいと思います。

    • 投稿ポイント: 0
  • 2009/6/24 12:16 返信先

    • seiryu
    • Top 25 Contributor
    • Joined on 2009/6/23
    • 訪問者級
    • ポイント 0

    Re: 自作アセンブリからのオブジェクト生成に失敗する

     参考URLまで貼っていただき、ありがとうございます。
     マルチモジュールアセンブリは同一フォルダに置くのがよいと思っていたのですが、そんなに単純ではないのですね。非常に勉強になりました。

     URLの記事を読んだ上で、もしやと思い、PowerShellの実行ファイルが格納されているフォルダ(自分の環境では、”C:\WINDOWS\system32\windowspowershell\v1.0”)に、自作アセンブリ2個(MyLib.dllとMyLib2.dll)をコピーし、コピーしたアセンブリをLoadFileして試したところ、エラーなくオブジェクトが生成されました。
     対処方法としては今ひとつといった感じですが、実現可能な方法が見つかったので少し満足しております。

     PowerShellに対して、アセンブリを検索するパスを指定するような配置場所に限定されない方法がベストですので、もう少し勉強してみます。

    • 投稿ポイント: 0
  • 2009/6/24 12:28 返信先

    Re: 自作アセンブリからのオブジェクト生成に失敗する

     >PowerShellの実行ファイルが格納されているフォルダ(自分の環境では、”C:\WINDOWS\system32\windowspowershell\v1.0”)に、自作アセンブリ2個(MyLib.dllとMyLib2.dll)をコピーし、

    なるほど。

    それは試してみませんでした。

    配置場所に限定されない方法あるといいですね。

    seiryuさん、もし解決したら教えて下さいね。

    私の方でももう少し調査してみたいと思います。

     

    • 投稿ポイント: 0
  • 2009/7/4 1:32 返信先

    • けろ-みお
    • Top 10 Contributor
      女性
    • Joined on 2008/12/18
    • techbank.jp 副管理人
    • 責任者級
    • ポイント 0
    • Bloggers
      Moderator
      MVP
      techbank

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    HIRO:

    配置場所に限定されない方法あるといいですね。

    試してませんが、もしかすると、%PATH% 環境変数で定義されている場所であれば・・・ とか、

    関係ありますかね?

    最悪、GACに登録してしまえば、配置場所問わずにすることはできますけど、

    それも大袈裟ですかね。機会があればお試し頂きたいです。

    • 投稿ポイント: 0
  • 2009/7/4 11:35 返信先

    • seiryu
    • Top 25 Contributor
    • Joined on 2009/6/23
    • 訪問者級
    • ポイント 0

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    けろ-みおさんコメントありがとうございます。

    PATH環境変数に関しては真っ先に確認しましたが、NGでした。
    次に、MyLib、MyLib2に署名して試しましたが、NGでした。
    最後に、GACに登録して試してみたところ、予想通りOKとなりました。

    ただ、少し意外な動きでした。

    【スクリプト例】
    [System.Reflection.Assembly]::LoadFile("C:\data\MyLib.dll")
    [System.Reflection.Assembly]::LoadFile("C:\data\MyLib2.dll")
    $obj1 = New-Object MyLib.MyClass1
    $obj2 = New-Object MyLib.MyClass2

    【出力】
    GAC    Version        Location                                                                                                  
    ---    -------        --------                                                                                                  
    True   v2.0.50727     C:\Windows\assembly\GAC_MSIL\MyLib\1.0.0.0__・・・\MyLib.dll                                    
    True   v2.0.50727     C:\Windows\assembly\GAC_MSIL\MyLib2\1.0.0.0__・・・\MyLib2.dll                                  

    LoadFileで明示的にパスを指定してLoadしてもGAC側のアセンブリが優先されるのは、わかりにくい仕様ですね。


    ①GACに登録する。
    ②PowerShellのパスにアセンブリをコピーする。

    現在のところ、上記2つの方法から選択することになるのですが、②をするくらいなら①のGACだと思いますので、必要に迫られた場合にはGACに登録する方法で運用しようと思います。

    もしも他に方法が見つかりましたら、ご教授いただきますようお願いいたします。

    • 投稿ポイント: 0
  • 2009/7/7 10:19 返信先

    • けろ-みお
    • Top 10 Contributor
      女性
    • Joined on 2008/12/18
    • techbank.jp 副管理人
    • 責任者級
    • ポイント 0
    • Bloggers
      Moderator
      MVP
      techbank

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    seiryu:

    【スクリプト例】
    [System.Reflection.Assembly]::LoadFile("C:\data\MyLib.dll")
    [System.Reflection.Assembly]::LoadFile("C:\data\MyLib2.dll")
    $obj1 = New-Object MyLib.MyClass1
    $obj2 = New-Object MyLib.MyClass2                        

    LoadFileで明示的にパスを指定してLoadしてもGAC側のアセンブリが優先されるのは、わかりにくい仕様ですね。

    GACに登録したアセンブリは、LoadFile不要です。

    そのままNew-Objectでインスタンス作れるはずです。

    それから、GACに登録したアセンブリキャッシュが残っていれば、

    いくらLoadFileしても、アセンブリキャッシュの内容が優先されるのはレスポンス/パフォーマンスの向上や

    セキュリティの向上が見込めるため、そのような仕様になっていると言えば、ご理解頂けますか?

    そう考えれば、「わかりにくい仕様」という疑問は解けるかと思います。

     

    それから、気になったんですが、

    MyLib.dll 内の実装コード(C#)で、MyLib2.dll を動的にLoadFile するように作りこんでしまえば、

    dll の配置場所は別にどこでも良いような気がしました。(もちろん、GAC登録も不要です)

     

    今、PowerShellとVisual Studio がないPCで書き込んでいるので、裏付けはとってないんですが、

    良かったら確認してみてください。

    • 投稿ポイント: 0
  • 2009/7/7 23:16 返信先

    • seiryu
    • Top 25 Contributor
    • Joined on 2009/6/23
    • 訪問者級
    • ポイント 0

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    けろ-みおさん、ご教授ありがとうございます。
    GACを文字通りキャッシュと思えばよいのですね。すっきりしました。

    けろ-みお:

    MyLib.dll 内の実装コード(C#)で、MyLib2.dll を動的にLoadFile するように作りこんでしまえば、

    dll の配置場所は別にどこでも良いような気がしました。(もちろん、GAC登録も不要です)

    MyLib.dllから、単純にMyLib2.dll内のクラスを利用するのであれば動的にLoadFileするコードは書けそうなのですが、継承クラスを作成する場合、どのように記述すればよいのかわかりませんでした。
    具体的にどのように実装することになるのでしょうか?

    • 投稿ポイント: 0
  • 2009/7/9 11:13 返信先

    • けろ-みお
    • Top 10 Contributor
      女性
    • Joined on 2008/12/18
    • techbank.jp 副管理人
    • 責任者級
    • ポイント 0
    • Bloggers
      Moderator
      MVP
      techbank

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    seiryu:

    MyLib.dllから、単純にMyLib2.dll内のクラスを利用するのであれば動的にLoadFileするコードは書けそうなのですが、継承クラスを作成する場合、どのように記述すればよいのかわかりませんでした。
    具体的にどのように実装することになるのでしょうか?

    なるほど。そう言われると確かに困りますね。seiryuさんのおっしゃる通りです。

    問題を軽く考えていたため、回答が雑になってしまいました。申し訳ございません。

    さて、解決策ですが、下記の通りです。

    早い話が、PowerShell本体 が、MyLib2.dll で定義されている継承元クラスが参照できるようにすれば、

    MyLib.dll から、MyLib2.dll を参照しても問題ない設定をすれば、解決できます。

     

    問題のライブラリ(MyLib.dll,  MyLib2.dll )  ※C#側のソース修正は不要

    //自作アセンブリ MyLib.dll
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using MyLib2;
     
    namespace MyLib
    {
        public class MyClass1
        {
            public void Test1()
            {
                Console.WriteLine("HELLO TEST1");
            }
        }
        public class MyClass2 : MyClass0
        {
            public void Test2()
            {
                Console.WriteLine("HELLO TEST2");
            }
        }
    }
     
    //自作アセンブリ MyLib2.dll
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace MyLib2
    {
        public class MyClass0
        {
            public void Test0()
            {
                Console.WriteLine("HELLO TEST0");
            }
        }
    }

     

    そして、下記のようなPowerShellコード(*.ps1ファイル)を実行すると、継承元クラスが参照できない問題はなくなり

    お望み通り動くようになります。(LoadFile となっていた箇所を LoadFrom に変更してみてください。)←下記返信スレッドに記載した内容です。

    [System.Reflection.Assembly]::LoadFrom("C:\work\MyLib2.dll")
    [System.Reflection.Assembly]::LoadFrom("C:\work\MyLib.dll")
     
    $obj1 = New-Object MyLib.MyClass1
    $obj2 = New-Object MyLib.MyClass2
     
    $obj1.Test1(); 
    $obj2.Test2();
    $obj2.Test0();

     

    実行結果:

     

    もし、これでやってみてもダメだった場合は、ご連絡下さい。宜しくお願いします。

     

    分類:
    • 投稿ポイント: 0
  • 2009/7/9 16:58 返信先

    • けろ-みお
    • Top 10 Contributor
      女性
    • Joined on 2008/12/18
    • techbank.jp 副管理人
    • 責任者級
    • ポイント 0
    • Bloggers
      Moderator
      MVP
      techbank

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    失礼しました。PowerShell.exe.config に内容を記述しなくても大丈夫でした。

    (なので、上記のPowerShell.exe.config の欄は無視してください。

    現在は既に修正しましたが、このスレのRSSや通知メールでは、

    PowerShell.exe.config の対応が掲載されたものが配信されているため、念のため訂正させて頂きます。)

     

    正式回答としては、LoadFileでDLLを読み込もうとしていたために出ていたエラーなので、

    PowerShell で記述したLoadFileの箇所をLoadFromに変更して実行してみてください。

    そうするとうまくいくはずです。

     

    二転三転してしまい、すいませんでした。改めてお詫び申し上げます。

    分類:
    • 投稿ポイント: 0
  • 2009/7/9 20:55 返信先

    • seiryu
    • Top 25 Contributor
    • Joined on 2009/6/23
    • 訪問者級
    • ポイント 0

    Re: 自作アセンブリからのオブジェクト生成に失敗する

    けろ-みおさん、丁寧かつベストの回答をいただき、感謝いたします。

    たまたまどこかのサンプルで確認した、LoadFileで読み出す方法を利用し、LoadFileLoadFromには特に違いはないと勝手に思い込んでいたのが大きな間違いだったようです。
    アセンブリのロードは奥が深いことが、よくわかりました。

    また何かの壁にぶつかりましたら質問させてください。どうもありがとうございました。

    • 投稿ポイント: 0
Page 1 of 1 (13 items)
掲示板の人気度
フィードメーター - techbank.jpコミュニティ
Blog全体の人気度
フィードメーター - techbank.jpコミュニティ
スカウター : techbank.jp Powered by PR-Icon