none
非同期プログラム(動的)の返り値について RRS feed

  • 質問

  • 動的DLLを作成し、パラメータを渡した後の結果を呼び出し元に返したいのですが

    どうやってもうまくいきません。

    ステップデバック上で form.LabelText の中に意図する値が出ているのですが当然、

    暗黙的なメンバーではないのでコンパイルすると弾かれてしまいます。

     

    以下も試みてみましたが、やはりステップデバック上でしか見る事ができません。

    ((testform.form1)(Form))LabelText

    ちなみに以下のサンプルでは旨く動くのですがInvokeMemberは多用しない方が

    良いという記事を見かけたことがあり、使用していません。

    (複数のDLLを作って呼び出しを行います。)

    http://mag.autumn.org/Content.modf?id=20040530223210

     

    何か良い方法があれば御教授頂ければありがたいです。

     

     

    呼び出し元

    Code Snippet

    using System;

    using System.Reflection;

    namespace sample
    {
        ///
        /// Class1 の概要の説明です。
        ///
        class Class1
        {
            ///
            /// アプリケーションのメイン エントリ ポイントです。
            ///
            [STAThread]
            static void Main(string[] args)
            {
                //
                // TODO: アプリケーションを開始する・・・
                //

                try
                {
                    // アセンブリをロード
                    Assembly assembly =
                    Assembly.LoadFrom("testform.dll");

                    // アセンブリ内のモジュールを取得
                    // 通常は、ファイル名と同じ
                    Module module =
                        assembly.GetModule("testform.dll");
                    // アセンブリ内のクラスを取得
                    // ネームスペースを含めた完全なクラス名で
                    // 指定する
                    System.Type type =
                        module.GetType("testform.Form1");
                    if (type != null)
                    {
                        // クラスを動的に作成する
                        Object form = Activator.CreateInstance(type);
                        // クラス内のメソッドを取得する
                        // ここでは、引数がない[ShowDialog()]を
                        // 取得する
                        // そのため、2番目の引数は、空配列となる
                        MethodInfo ShowDialogMethod = type.GetMethod("ShowDialog", new Type[0]);
                        // クラス内のプロパティを取得する
                        PropertyInfo LabelText = type.GetProperty("LabelText");

                        // プロパティを設定
                        LabelText.SetValue(form, "動的呼び出し!!", null);

     

               ↑ LabelTextの値がform.LabelTextで返却される


                        System.Diagnostics.Debug.Write(LabelText);
                        // メソッドを呼び出す
                        ShowDialogMethod.Invoke(form, null);
                    }
                }
                catch (Exception ee)
                {
                    System.Diagnostics.Debug.Write(ee.Message);
                }
            }
        }
    }

     

     

     

     

    呼び出されるDLL

    Code Snippet

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;

    namespace testform
    {
        ///
        /// Form1 の概要の説明です。
        ///
        public class Form1 : System.Windows.Forms.Form
        {
            private System.Windows.Forms.Label label1;
            ///
            /// 必要なデザイナ変数です。
            ///
            private System.ComponentModel.Container components =  null;

            public string LabelText
            {
                set
                {
                    label1.Text = value;
                   
                }
                get {
                   return "5555555hhh"; ← これを返却したい
                }
            }

            public Form1()
            {
                //
                // Windows フォーム デザイナ サポートに必要です。
                //
                InitializeComponent();

                //
                // TODO: InitializeComponent 呼び出しの後に、・・
                //
            }

            ///
            /// 使用されているリソースに後処理を実行します。
            ///
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    if (components != null)
                    {
                        components.Dispose();
                    }
                }
                base.Dispose(disposing);
            }

            #region Windows フォーム デザイナで生成されたコード
            ///
            /// デザイナ サポートに必要なメソッドです。・・・
            /// コード エディタで変更しないでください。
            ///
            private void InitializeComponent()
            {
                this.label1 = new System.Windows.Forms.Label();
                this.SuspendLayout();
                //
                // label1
                //
                this.label1.Location =
                        new System.Drawing.Point(40, 32);
                this.label1.Name = "label1";
                this.label1.Size =
                        new System.Drawing.Size(136, 64);
                this.label1.TabIndex = 0;
                this.label1.Text = "label1";
                //
                // Form1
                //
                this.AutoScaleBaseSize =
                        new System.Drawing.Size(5, 12);
                this.ClientSize =
                        new System.Drawing.Size(216, 142);
                this.Controls.Add(this.label1);
                this.Name = "Form1";
                this.Text = "Form1";
                this.ResumeLayout(false);

            }
            #endregion
        }
    }

     

     

     

     

    2008年2月8日 15:45

回答

  • Class1 では ConsoleApplication3.IDialogValue を使用していて、Form1 では IDialogValue.IDialogValue を使用しているのが問題です。たんに名前が違うからというわけではなく、完全に同一のものを使わなければ型としては異なるものとして扱われます。
     
    また、インターフェースは必ず実装しなければなりませんので、継承元が Object であっても、
     
    public class Form1 : IDialogValue
     
    または、
     
    public class Form1: object, IDialogValue
     
    とする必要があります。(上側の記述は継承元の記述省略しているだけなので、この2つはまったく同じです)
     
    前の投稿に
     
    > 参照できる共通アセンブリを作成し、
     
    と書いているように、通常は3つのアセンブリ構成になります。
     
    1. Class1 があるアセンブリ (*.exe)
    2. Form1 があるアセンブリ (*.dll)
    3. IDialogValue があるアセンブリ (*.dll)
     
    です。IDialogValue を 1. のアセンブリに含めて、2. のアセンブリから 1. のアセンブリを参照設定するという手もあります。
     
    2008年2月11日 6:51
  •  穂樹 さんからの引用

    やはり参照設定は必要なのでしょうか・・・

    .NETで作成した型を共有するためには、アセンブリを参照することが必要不可欠です。

     

    リフレクションでやれば参照せずともできますが、その型が目的のメソッド・プロパティを実装しているかどうか、引数の数が正しいかどうか、戻り値の型が正しいかどうかのチェックが細かく必要になるので、手間がかかります。

    (その名前で取得できたからといって、求めている関数仕様とは限らない)

     

     穂樹 さんからの引用

    APIの様にコンパイル時に依存関係を持たない方法があれば御教授頂けるとありがたいです。

    APIは関数単位ですが引数や戻り値という情報(インターフェース)をコード上で共有していますよね?

    そういった意味ではコンパイル時に一定の依存関係はあると考えます。

    (ヘッダーファイルやDllImportといった弱い依存かもしれませんが)

    2008年2月16日 10:16
    モデレータ
  •  穂樹 さんからの引用

    例えば、レジストリにDLLを登録する事で、参照設定を免れる事は可能でしょうか?

    できません。

    レジストリに登録するのはCOMとして公開する場合だけのはずです。

    (今回の目的にレジストリ登録の有無は影響しません)

     

     穂樹 さんからの引用

    ・DLLを複数作る時に依存が出来ると全てのプロジェクトを再コンパイルする必要が生じ、面倒

    全てのプロジェクトというのは具体的に何を指していますか?

    インターフェースプロジェクトと、アプリケーションプロジェクト(exe)と、複数の機能実装プロジェクト(dll)が1つのソリューションになっていて、依存関係を作っているから、「実行」を指示すると全てコンパイルが走ると言うことですか?

     

    私の認識(想定)

    ・インターフェースだけを含むプロジェクト(InterfaceProject)がある。

    ・アプリケーションプロジェクト(ApplicationProject)は、InterfaceProjectだけを参照する。

    ・機能実装プロジェクト(LibraryProject)は、InterfaceProjectだけを参照する。

    ・ApplicationProjectは実行時に、同じフォルダにあるdllファイルを読み出し(Assemblyクラスを使う)、InterfaceProjectにあるインターフェースの型を実装しているか確認し、実装されていればその型のメソッドを呼ぶ。

     

    こういう構成であるならば、ApplicationProjectとLibraryProjectとの間には直接の依存関係はありません。

    また、直接の依存関係がない場合は「実行時に、スタートアップ プロジェクトおよび依存関係のみをビルドする」を有効にしておけば、開発時の再コンパイル量も減ると思われます。

     

    参考:http://msdn2.microsoft.com/ja-jp/library/cyhcc7zc(VS.80).aspx

    2008年2月17日 14:25
    モデレータ
  •  穂樹 さんからの引用

    なるほど・・・ということはCOM DLLを作成すれば直接参照しない作り方ができるという事でしょうか?

    このスレッド本来の質問趣旨からズレている様で申し訳ないですがご回答頂ければ非常に有難いです。

    C#を含む.NET系言語はCOMを使用する際に参照設定(マネージラッパーDLL、RCW)が必要です。

    よって、C# COM DLLにするメリットはありません。

     

    RCW(Runtime Callable Wrapper)

    http://msdn2.microsoft.com/ja-jp/library/8bwh56xe(VS.80).aspx

     

     穂樹 さんからの引用

    これを見る限り、Cでなければ無理かと半分諦めてはいますが。

    DllImportやGetProcAddressで呼び出せる形のDLLをC#で作ることはできません。

    C#で開発する限り、参照設定を不要にすることは基本的にできません。(リフレクションでやる場合を除きます)

     

    #マネージというコードの安全性を求める以上は仕方ない?

     

     穂樹 さんからの引用

    しかし、中間にインターフェイスDLLがあり、参照設定がされている以上はインターフェイスとDLLとEXE全てを再コンパイルする必要があると私は認識していました。

    (まだ設計すらできていないのですが現状、開発していく段階でDLLの追加やパラメータの仕様変更は必然的に起こります。)

    開発段階等でインターフェースDLLが更新されるのであれば、その度に実装するDLLと使用するEXEのコンパイルは必要です。

    再コンパイルしないと、EXE側はその追加されたインターフェースを利用できませんし、DLL側は増えたメソッドをサポートしていないクラスができあがることになります。

     

    特定のインターフェースは参照するが、その他のインターフェースは参照しないといったDLLが複数タイプ存在するのであれば、インターフェースプロジェクトを複数に分割することも手だとは思いますが、細かく分割すると手間も増えてきます。

    要求や設計次第で変わってくると思いますので、どうするのが良いとは一概に言えるものではありませんが…。
    2008年2月21日 16:10
    モデレータ
  • Azulean様、最後までお付き合い頂き本当に有難うございました。

     

    上記の件、よく理解できました。

    今後、上記の参照設定またはリフクレクションで開発するかどうかは不明ですが、

    設計の指針を立てる上で非常に貴重な情報を得る事ができました。

    改めてお礼を申し上げます。

    2008年2月22日 12:08

すべての返信

  • 穂樹 さん、こんにちは

    ダッチです。

     

    まず、こちらの処理で行っているのは Form1 クラスの LabelText プロパティに値を設定しています。

     

    プロパティの Set を呼び出し
    LabelText.SetValue(form, "動的呼び出し!!", null);

    // 動的に呼び出しを行わない場合は次の処理と同じです。

    form.LabelText = "動的呼び出し!!";

     

    当然ながらプロパティに値を設定しても結果は返ってきません。 

    プロパティに設定した値を取得したい場合は GetValue メソッドを使用してプロパティを値を取得します。

     

    プロパティの Get を呼び出し
    string labelText = (string)LabelText.GetValue(form, null);

    // 動的に呼び出しを行わない場合は次の処理と同じです。

    string labelText = form.LabelText;

     

    labelText 変数には "動的呼び出し!!" が入ってくるはずです。

     

     

    今回、穂樹 さんがやりたいことはどうもプロパティを操作するというよりはメソッドに値を渡して、その結果を取得したいように見えました。(ちょっと LabelText プロパティの役割が見えてきませんでしたので詳細はわかりません。)

     

    この場合は MethodInfo クラスを使用して動的にそのメソッドを呼び出してやれば結果を取得することができます。

     

    メソッドの呼び出し

    public string TextMethod(string value) { return "5555555hhh"; }

     

    MethodInfo mi = form.GetMethod("TextMethod");
    if (mi != null)
    {
        string result = (string)mi.Invoke(form, new object[] { "動的呼び出し!!"});
    }

    // 動的に呼び出しを行わない場合は次の処理と同じです。

    string result = form.TextMethod("動的呼び出し!!");

     

    result 変数には "5555555hhh" が入ってきます。

    ただこの例では TextMethod メソッドに渡した引数("動的呼び出し!!")は、なにも使用していません。

    2008年2月9日 1:39
  • まず、第一に、
     
    > 動的DLLを作成し、パラメータを渡した後の結果を呼び出し元に返したい
     
    という目的に対してリフレクションを利用するのが方向性としてはおかしいと思います。
    もちろん、手段としての1つではあるのですが、選択肢としては選ばないのが通常だろうと思います。
     
    他の方法としてインターフェースや基底クラスを利用することができます。
    たとえばインターフェースを利用する場合、2つのアプリケーション双方から参照できる共通アセンブリを作成し、
     
    Code Snippet
    public interface IDialogValue
    {
      // プロパティとして公開する場合
      string LabelText { get; set }
     
      // メソッドとして公開する場合
      void SetLabelText(string text);  // 設定
      string GetLabelText();           // 取得
     
      // 既存の使用したい public method を記載しておくと、便利になる
      DialogResult ShowDialog();
      DialogResult ShowDialog(IWin32Window owner);
    }

     

     

    のようなインターフェースを作成しておいて、
     
    Code Snippet
    // 上記のインターフェースを実装する
    public class Form1 : System.Windows.Forms.Form, IDialogValue
    {
     
      // プロパティの場合の実装

      public string LabelText
      {
        set { label1.Text = value; }

        get { return "5555555hhh"; }
      }

     

      // メソッドの場合の実装

      public void SetLabelText(string text)

      {

        label1.Text = text;

      }

     

      // GetLabelText は略

     

     

     

    のように、呼び出される側に実装しておきます。使う側は、インスタンス生成にて

     

    Code Snippet

    IDialogValue dialog = Activator.CreateInstance(type) as IDialogValue;

     

    // プロパティとして設定する

    dialog.LabelText = "動的呼び出し"

     
    // ダイアログを表示する
    dialog.ShowDialog();

     

    // もちろん取得もできる

    Debug.WriteLine(dialog.LabelText);

     

    のように利用します。

     
     
    2008年2月9日 7:29
  • ダッチ様、K.Takaoka様、回答ありがとうございます。

     

    >リフレクションを利用するのが方向性としてはおかしいと思います。

    はい、その通りだと思います、インターフェイスを使った方がシンプルですね。

    VB6から移った者でクラスの概念などあるべき姿がまだ良く理解ができていないと思います。

    申し訳ないですがもう少しお付き合い頂ければ幸いです。

     

    K.Takaoka様の内容の通り、呼び出し元と先にインターフェイスを実装してテストを行いました。

    但し、以下の所でインターフェイスを実装する所でdialogの中身がNULLのまま

    dialog.LabelTextを呼び出せない状態です。

     

    IDialogValue dialog = Activator.CreateInstance(type) as IDialogValue;

     

    Activator.CreateInstance(type)の中身はDLLを参照している様なのでインターフェイスの定義がおかしいのか

    或いは何かが抜けているのだと思います。

    もう少し調べてみますが御教授頂ければありがたいです。

     

    (public class Form1 : System.Windows.Forms.Form, IDialogValueのフォームのソースは削除したため、継承は削除しています。)

     

    呼び出し元

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

    namespace ConsoleApplication3
    {
        ///
        /// Class1 の概要の説明です。
        ///
        public interface IDialogValue
        {
            //string LabelText
            //{
            //    get;
            //    set;
            //}

            // メソッドとして公開する場合
            void SetLabelText(string text);  // 設定
            string GetLabelText();           // 取得
        }
        class Class1
        {


            ///
            /// アプリケーションのメイン エントリ ポイントです。
            ///
            [STAThread]
            static void Main(string[] args)
            {
                //
                // TODO: アプリケーションを開始する・・・
                //

                try
                {
                    // アセンブリをロード
                    Assembly assembly = Assembly.LoadFrom("IDialogValue.dll");

                    // アセンブリ内のモジュールを取得
                    // 通常は、ファイル名と同じ
                    Module module = assembly.GetModule("IDialogValue.dll");
                    // アセンブリ内のクラスを取得
                    // ネームスペースを含めた完全なクラス名で
                    // 指定する
                    System.Type type = module.GetType("IDialogValue.Form1");
                    IDialogValue dialog = Activator.CreateInstance(type) as IDialogValue;

                                  ↑ここでインスタンスを生成してもNULL
                    if (type != null)
                    {
                        // プロパティとして設定する

                        //dialog.LabelText = "動的呼び出し";


                   dialog.SetLabelText("動的呼び出し");                    

                         ↑dialogがNULLなので呼び出せない。


                        //// もちろん取得もできる
                        //System.Diagnostics.Debug.Write(dialog.LabelText);

                    }
                }
                catch (Exception ee)
                {
                    System.Diagnostics.Debug.Write(ee.Message);
                }
            }
        }
    }

     

     

     

    呼び出し先
    using System;
    using System.Collections.Generic;
    using System.Text;
    using IDialogValue;
    namespace IDialogValue
    {
        public interface IDialogValue
        {
            // メソッドとして公開する場合
            void SetLabelText(string text);  // 設定
            string GetLabelText();           // 取得
        }
        public class Form1
        {
         
          public string grName;
          // メソッドの場合の実装
          public void SetLabelText(string text)
          {
              grName = grName + text;
          }
          public string GetLabelText
          {
              get { return grName + "5555555hhh"; }
          }
        }
    }

     

     

    2008年2月9日 16:25
  • Class1 では ConsoleApplication3.IDialogValue を使用していて、Form1 では IDialogValue.IDialogValue を使用しているのが問題です。たんに名前が違うからというわけではなく、完全に同一のものを使わなければ型としては異なるものとして扱われます。
     
    また、インターフェースは必ず実装しなければなりませんので、継承元が Object であっても、
     
    public class Form1 : IDialogValue
     
    または、
     
    public class Form1: object, IDialogValue
     
    とする必要があります。(上側の記述は継承元の記述省略しているだけなので、この2つはまったく同じです)
     
    前の投稿に
     
    > 参照できる共通アセンブリを作成し、
     
    と書いているように、通常は3つのアセンブリ構成になります。
     
    1. Class1 があるアセンブリ (*.exe)
    2. Form1 があるアセンブリ (*.dll)
    3. IDialogValue があるアセンブリ (*.dll)
     
    です。IDialogValue を 1. のアセンブリに含めて、2. のアセンブリから 1. のアセンブリを参照設定するという手もあります。
     
    2008年2月11日 6:51
  •  

    K.Takaoka 様 親切な回答をありがとうございます。

    以下の通りに作って動きました。

     

    ※色々探し回ってサンプルを抜き出したりした結果、プロジェクトの名前などが変わっていますがご容赦ください。

     

    インターフェイス(plugin.dll)

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


        public interface IPlugin
        {
            // このプラグインが,filename をサポートするなら true.
            bool IsSupported(string filename);
        }

     
     

    呼び出し先(a_plugin.dll)
    using System;
    using System.Collections.Generic;
    using System.Text;
    namespace Plugin
    {
        public class CPlugin : IPlugin
        {
            public object IsSupported(string filename)
            {
                    return  "てすと";
            }
        }
    }
     

     

    Code Snippet

    using System;
    using System.IO;
    using System.Reflection;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;
    using System.Drawing;

    namespace Plugin
    {

        public class DllName
        {
            public const string Cs_a_plugin = "a_plugin.dll";
            public const string Cs_GetType = "Plugin.CPlugin";
        }

        public class Loader
        {
            static void Main(string[] args)
            {
                try
                {
                    // アセンブリをロード
                    Assembly assembly =
                    Assembly.LoadFrom(DllName.Cs_a_plugin);

                    // アセンブリ内のモジュールを取得
                    // 通常は、ファイル名と同じ
                    Module module =
                        assembly.GetModule(DllName.Cs_a_plugin);
                    // アセンブリ内のクラスを取得
                    // ネームスペースを含めた完全なクラス名で
                    // 指定する
                    System.Type type = module.GetType(DllName.Cs_GetType);
                   
                    if (type != null)
                    {

                        // プロパティを設定
                        IPlugin dialog = Activator.CreateInstance(type) as IPlugin;
                        object bol_Test;
                      
                        bol_Test = dialog.IsSupported("");
                        MessageBox.Show(bol_Test.ToString());
                        System.Console.WriteLine(bol_Test.ToString());
                    }
                }
                catch (Exception ee)
                {
                    System.Diagnostics.Debug.Write(ee.Message);
                }
            }
        }
    }

     

     

     

     

    結局、インターフェイスアセンブリを呼び出し元と呼び出し先に参照設定する事で動いたのですが

    やはり参照設定は必要なのでしょうか・・・

     

    私がまた何かを誤解して作っているのか、DLLを増やす毎にコンパイルの回数が増えてしまうので

    APIの様にコンパイル時に依存関係を持たない方法があれば御教授頂けるとありがたいです。

    しばらく、解決方法がないか探してみます、本当にありがとうございました。

     

     

    2008年2月16日 2:10
  •  穂樹 さんからの引用

    やはり参照設定は必要なのでしょうか・・・

    .NETで作成した型を共有するためには、アセンブリを参照することが必要不可欠です。

     

    リフレクションでやれば参照せずともできますが、その型が目的のメソッド・プロパティを実装しているかどうか、引数の数が正しいかどうか、戻り値の型が正しいかどうかのチェックが細かく必要になるので、手間がかかります。

    (その名前で取得できたからといって、求めている関数仕様とは限らない)

     

     穂樹 さんからの引用

    APIの様にコンパイル時に依存関係を持たない方法があれば御教授頂けるとありがたいです。

    APIは関数単位ですが引数や戻り値という情報(インターフェース)をコード上で共有していますよね?

    そういった意味ではコンパイル時に一定の依存関係はあると考えます。

    (ヘッダーファイルやDllImportといった弱い依存かもしれませんが)

    2008年2月16日 10:16
    モデレータ
  • Azulean様、親切な回答をありがとうございます。

    上記の件、よく理解できました。

     

    そもそも、ここで質問した内容に意図を書いてなかったのはまずかったと思いました。

    パッケージを作るときに共通となる部品をDLL化するつもりでいました、それは以下の理由からです。

     

    ・参照設定には設定数に限度がある事を知っていたため、汎用に向かない

    ・DLLを複数作る時に依存が出来ると全てのプロジェクトを再コンパイルする必要が生じ、面倒

    ・EXEにあまり常時使わない画像や関数などは置きたくない(実行時に不要なメモリー消費をしたくない)

    (過去、VBで複数の画面やコントロールをEXEの中に詰め込んだとき、立ち上がりが重くサクサク動かなかったため)

     

    例えば、レジストリにDLLを登録する事で、参照設定を免れる事は可能でしょうか?

    LHAユーティリティなどでDLLを追加すれば参照出来るような作り方をしたかったのです。

    もし、知っておられる方がいましたら返信をお願い致します。
    2008年2月17日 14:08
  •  穂樹 さんからの引用

    例えば、レジストリにDLLを登録する事で、参照設定を免れる事は可能でしょうか?

    できません。

    レジストリに登録するのはCOMとして公開する場合だけのはずです。

    (今回の目的にレジストリ登録の有無は影響しません)

     

     穂樹 さんからの引用

    ・DLLを複数作る時に依存が出来ると全てのプロジェクトを再コンパイルする必要が生じ、面倒

    全てのプロジェクトというのは具体的に何を指していますか?

    インターフェースプロジェクトと、アプリケーションプロジェクト(exe)と、複数の機能実装プロジェクト(dll)が1つのソリューションになっていて、依存関係を作っているから、「実行」を指示すると全てコンパイルが走ると言うことですか?

     

    私の認識(想定)

    ・インターフェースだけを含むプロジェクト(InterfaceProject)がある。

    ・アプリケーションプロジェクト(ApplicationProject)は、InterfaceProjectだけを参照する。

    ・機能実装プロジェクト(LibraryProject)は、InterfaceProjectだけを参照する。

    ・ApplicationProjectは実行時に、同じフォルダにあるdllファイルを読み出し(Assemblyクラスを使う)、InterfaceProjectにあるインターフェースの型を実装しているか確認し、実装されていればその型のメソッドを呼ぶ。

     

    こういう構成であるならば、ApplicationProjectとLibraryProjectとの間には直接の依存関係はありません。

    また、直接の依存関係がない場合は「実行時に、スタートアップ プロジェクトおよび依存関係のみをビルドする」を有効にしておけば、開発時の再コンパイル量も減ると思われます。

     

    参考:http://msdn2.microsoft.com/ja-jp/library/cyhcc7zc(VS.80).aspx

    2008年2月17日 14:25
    モデレータ
  • Azulean様、丁寧なご回答を有難うございます。

     

    >レジストリに登録するのはCOMとして公開する場合だけのはずです。

    なるほど・・・ということはCOM DLLを作成すれば直接参照しない作り方ができるという事でしょうか?

    このスレッド本来の質問趣旨からズレている様で申し訳ないですがご回答頂ければ非常に有難いです。

    (私はVB6で似た様な作り方でCOMDLL(?)を扱った覚えがあります(バッチでdll名をレジストリに登録しました)が経験上、

     参照設定は逃れられないのかなぁと認識しています。)

    http://www.ne.jp/asahi/yamashita/programming/dot_net/dll.html

    これを見る限り、Cでなければ無理かと半分諦めてはいますが。

     

    >こういう構成であるならば、ApplicationProjectとLibraryProjectとの間には直接の依存関係はありません。

    例えば、DLLとEXE自体には依存関係の無い事は認識しています。

    しかし、中間にインターフェイスDLLがあり、参照設定がされている以上はインターフェイスとDLLとEXE全てを再コンパイルする必要があると私は認識していました。

    (まだ設計すらできていないのですが現状、開発していく段階でDLLの追加やパラメータの仕様変更は必然的に起こります。)

     

    >また、直接の依存関係がない場合は・・・

    これは知りませんでした、早速試してみようと思います。

     

    上記3点、私には知識が無く、非常に有難い回答であると共に感謝しております。

    2008年2月21日 12:26
  •  穂樹 さんからの引用

    なるほど・・・ということはCOM DLLを作成すれば直接参照しない作り方ができるという事でしょうか?

    このスレッド本来の質問趣旨からズレている様で申し訳ないですがご回答頂ければ非常に有難いです。

    C#を含む.NET系言語はCOMを使用する際に参照設定(マネージラッパーDLL、RCW)が必要です。

    よって、C# COM DLLにするメリットはありません。

     

    RCW(Runtime Callable Wrapper)

    http://msdn2.microsoft.com/ja-jp/library/8bwh56xe(VS.80).aspx

     

     穂樹 さんからの引用

    これを見る限り、Cでなければ無理かと半分諦めてはいますが。

    DllImportやGetProcAddressで呼び出せる形のDLLをC#で作ることはできません。

    C#で開発する限り、参照設定を不要にすることは基本的にできません。(リフレクションでやる場合を除きます)

     

    #マネージというコードの安全性を求める以上は仕方ない?

     

     穂樹 さんからの引用

    しかし、中間にインターフェイスDLLがあり、参照設定がされている以上はインターフェイスとDLLとEXE全てを再コンパイルする必要があると私は認識していました。

    (まだ設計すらできていないのですが現状、開発していく段階でDLLの追加やパラメータの仕様変更は必然的に起こります。)

    開発段階等でインターフェースDLLが更新されるのであれば、その度に実装するDLLと使用するEXEのコンパイルは必要です。

    再コンパイルしないと、EXE側はその追加されたインターフェースを利用できませんし、DLL側は増えたメソッドをサポートしていないクラスができあがることになります。

     

    特定のインターフェースは参照するが、その他のインターフェースは参照しないといったDLLが複数タイプ存在するのであれば、インターフェースプロジェクトを複数に分割することも手だとは思いますが、細かく分割すると手間も増えてきます。

    要求や設計次第で変わってくると思いますので、どうするのが良いとは一概に言えるものではありませんが…。
    2008年2月21日 16:10
    モデレータ
  • Azulean様、最後までお付き合い頂き本当に有難うございました。

     

    上記の件、よく理解できました。

    今後、上記の参照設定またはリフクレクションで開発するかどうかは不明ですが、

    設計の指針を立てる上で非常に貴重な情報を得る事ができました。

    改めてお礼を申し上げます。

    2008年2月22日 12:08