none
c#でのusingディレクティブの適用範囲が分からない RRS feed

  • 質問

  • c#を始めたばかりの超初心者です。他にはVBAしか利用したことはありません。

    Visual Studio 2015 Professionalのc#で、Offie(Outlook2010)用の
    VSTOアドインのアプリケーションを開発しようと考えております。

    手始めに、以下のMSDNのサンプルプログラムの GetDistributionListMembers
    メソッドを試そうとしています。
    https://msdn.microsoft.com/en-us/library/cc513843(v=office.12).aspx
    ※サンプルはOutlook2007用ですが GetDistributionListMembers メソッドは
     Outlook2010でも動作するようです。今回はこの GetDistributionListMembers を
     利用しています。

    ところが、Visual Studioが自動生成したクラス(ThisAddIn)のメソッドとして
    追加した、サンプルプログラムは、正常に動作するのに、新しく追加した
    クラス(Class1)のメソッドとして利用しようとすると、IDEのソース編集画面で、
    以下ソースの17行目の Application.Session.GetSelectNamesDialog() の
    Application にマウスのカーソルを合わせると、以下の様な警告が表示されます。
    「class System.Windows.Forms.Applicaion
     Windows メッセージを処理するために、アプリケーションを開始および停止する
     メソッドや、アプリケーションの情報を取得するためのプロパティなど、
     アプリケーションを管理するための static メソッドおよびプロパティを
     提供します。このクラスは継承できません。」

    01|using System;
    02|using System.Collections.Generic;
    03|using System.Linq;
    04|using System.Text;
    05|using System.Threading.Tasks;
    06|using Office = Microsoft.Office.Core; // add
    07|using Outlook = Microsoft.Office.Interop.Outlook; // add
    08|using System.Windows.Forms; //add
    09|
    10|namespace OutlookAddIn1C2
    11|{
    12|    public class Class1
    13|    {
    14|
    15|        public void GetDistributionListMembers()
    16|        {
    17|            Outlook.SelectNamesDialog snd = Application.Session.GetSelectNamesDialog();
    18|            Outlook.AddressLists addrLists = Application.Session.AddressLists;

    そもそも、Application.Session.GetSelectNamesDialog() は、
    using Outlook = Microsoft.Office.Interop.Outlook でエイリアスされた
    Outlookのクラスのメソッドを指定していると、認識しているのですが、
    実際にはSystem.Windows.Formsの名前空間にあるApplicationメンバを
    参照しているように見えます。

    確かに、ソリューションエクスプローラーで System.Windows.Forms を参照すると
    (System.Windows.Formsには)Applicationメンバが存在します。
    ならば、エイリアスを明示的に指定すればよいのかと考え、
    Outlook.Application.Session.GetSelectNamesDialog()とすると、今度は、
    「interface Microsoft.Offie.Interrop.Outlook.Application
     Represents the entire Outlook Application.
     
     静的でないフィールド、メソッド、またはプロパティ '_Aoolication.
     ActiveExplorer()' で、オブジェクト参照が必要です」
    と表示されます。

    ・なぜ、サンプルプログラムは、Visual Studioが自動生成した
     クラス(ThisAddIn)のメソッドとしては正常動作し、
      新たに追加したクラス(Class1)に追加したサンプルのメソッドは
      動作しないのでしょうか?
      ※フレームワークは .NET Framework 4.5.2です。

    何か基本知識が足りないのだと思うのですが、それが何であるか
    いろいろと調べてみましたが、さっぱりわかりません。

    何を勘違いしていて、どんな基礎知識が足りないのか、
    教えていただきますよう、お願いいたします。

    2017年3月7日 2:53

回答

  • Visual Studio が自動生成したVSTOアドインのコードを見てみました。

    Outlook.SelectNamesDialog snd = Application.Session.GetSelectNamesDialog();

    上記のようなコードを書いた場合 Application の定義は Microsoft.Office.Interop.Outlook で定義されたものではなく、Visual Studio が自動生成したファイル ThisAddIn.Designer.cs の中で

    public sealed partial class ThisAddIn : Microsoft.Office.Tools.Outlook.OutlookAddInBase {
    ...
        internal Microsoft.Office.Interop.Outlook.Application Application;
    ...
    }

    Application インスタンスが定義されていました。名前解決の優先度は同一名前空間内にあるものが1番高いので、ThisAddin クラス内からは上記の Application が使われるようです。

    クラスや変数がどこで定義されているかを知るには、そのクラスや変数を選択して F12 キーを押すと定義に飛ぶことができます。

    参考サイト: http://ufcpp.net/study/csharp/sp_namespace.html#priority

    2017年3月7日 3:23
  • https://msdn.microsoft.com/ja-jp/library/microsoft.office.interop.outlook._application_members.aspx

    ApplicationがClass1のプロパティでないなら、インスタンスを作成せずにApplication.Session.GetSelectNamesDialog()の呼び出しが成功するためには、ApplicationかSessionはstaticである必要があります。

    最初のエラーは、ApplicationはstaticでないSystem.Windows.Forms.Applicationが見つかったので、staticメンバーのSessionを探したが見つからなかったというようなエラーが出ていたはずです。

    また、Microsoft.Office.Interop.Outlook.ApplicationはインターフェースなのでApplication.SessionのApplicationがMicrosoft.Office.Interop.Outlook.Applicationと解釈されることはないです。

    明示的に指定しても、インターフェースはstaticメンバーを持てないので、Application.Sessionのメソッドを呼び出せません。

    2つ目のエラーメッセージはそのことを言っているのだと思います。

    kenjinoteさんの指摘されているようにApplicationのインスタンスはThisAddIn.Applicationです。

    internalなので同じアセンブリならアクセス可能ですが、staticではないのでThisAddInから自作のクラスにThisAddIn.Applicationのインスタンスを渡してもらわないと使用できないと思います。

    public class Class1
    {
        internal Microsoft.Office.Interop.Outlook.Application Application { get; set }
    
        public SetApplication(Microsoft.Office.Interop.Outlook.Application application)
        {
            Application = application;
        }
    }

    ThisAddInからSetApplicationでthis.Applicationを渡したらよいでしょう。

    一旦、渡したらApplicationプロパティ経由でアクセスできると思います。



    2017年3月7日 14:54

すべての返信

  • Visual Studio が自動生成したVSTOアドインのコードを見てみました。

    Outlook.SelectNamesDialog snd = Application.Session.GetSelectNamesDialog();

    上記のようなコードを書いた場合 Application の定義は Microsoft.Office.Interop.Outlook で定義されたものではなく、Visual Studio が自動生成したファイル ThisAddIn.Designer.cs の中で

    public sealed partial class ThisAddIn : Microsoft.Office.Tools.Outlook.OutlookAddInBase {
    ...
        internal Microsoft.Office.Interop.Outlook.Application Application;
    ...
    }

    Application インスタンスが定義されていました。名前解決の優先度は同一名前空間内にあるものが1番高いので、ThisAddin クラス内からは上記の Application が使われるようです。

    クラスや変数がどこで定義されているかを知るには、そのクラスや変数を選択して F12 キーを押すと定義に飛ぶことができます。

    参考サイト: http://ufcpp.net/study/csharp/sp_namespace.html#priority

    2017年3月7日 3:23
  • kenjinote様

    迅速なご回答をありがとうございます。
    ご回答頂いた内容に返信するには、私自身で把握する必要があります。
    結果の報告は、もう少しお待ちいただけますか。

    まずは、お礼申し上げます。

    2017年3月7日 4:56
  • https://msdn.microsoft.com/ja-jp/library/microsoft.office.interop.outlook._application_members.aspx

    ApplicationがClass1のプロパティでないなら、インスタンスを作成せずにApplication.Session.GetSelectNamesDialog()の呼び出しが成功するためには、ApplicationかSessionはstaticである必要があります。

    最初のエラーは、ApplicationはstaticでないSystem.Windows.Forms.Applicationが見つかったので、staticメンバーのSessionを探したが見つからなかったというようなエラーが出ていたはずです。

    また、Microsoft.Office.Interop.Outlook.ApplicationはインターフェースなのでApplication.SessionのApplicationがMicrosoft.Office.Interop.Outlook.Applicationと解釈されることはないです。

    明示的に指定しても、インターフェースはstaticメンバーを持てないので、Application.Sessionのメソッドを呼び出せません。

    2つ目のエラーメッセージはそのことを言っているのだと思います。

    kenjinoteさんの指摘されているようにApplicationのインスタンスはThisAddIn.Applicationです。

    internalなので同じアセンブリならアクセス可能ですが、staticではないのでThisAddInから自作のクラスにThisAddIn.Applicationのインスタンスを渡してもらわないと使用できないと思います。

    public class Class1
    {
        internal Microsoft.Office.Interop.Outlook.Application Application { get; set }
    
        public SetApplication(Microsoft.Office.Interop.Outlook.Application application)
        {
            Application = application;
        }
    }

    ThisAddInからSetApplicationでthis.Applicationを渡したらよいでしょう。

    一旦、渡したらApplicationプロパティ経由でアクセスできると思います。



    2017年3月7日 14:54
  • tmori3y2さん
    kenjinoteさん

    返信が遅くなりまして、申し訳ございません。

    とても有用な情報をご提供いただき、ありがとうございます。
    USINGディレクティブの優先順位やなぜ動作しないかを
    理解することができました。
    ※インターフェースや静的クラスというキーワードに触れることが
     できました。

    tmori3y2さんのサンプルコードを利用して、
    ThisAddInクラスから(質問時のサンプルの)自作クラス(Class1)の
    MSDNのサンプル(GetDistributionListMembers)を呼び出すことができました。

    ところで、私がなぜ、ThisAddInクラス以外の自作クラスから、
    MSDNのサンプル(GetDistributionListMembers)を利用したかったからというと※
    リボンのボタンからフォームを呼び出してボタンを押すと、
    アドレス帳から選択したメールアドレスを取得したかったからです。
    ※教えていただいた内容から行くと、間違えているかもしれませんが、
     「Microsoft.Office.Interop.Outlook名前空間のApplicationインターフェイスを
     利用したかったか」ということですよね。

    kenjinoteさん,tmori3y2さんの指摘と助言を受けて、いろいろと
    調べてみると、MSDNには「VSTO アドイン プロジェクトの ThisAddIn クラス。
    このオブジェクトには、Globals.ThisAddIn プロパティを使用して
    アクセスすることができます。」と書いてあることに気が付きました。

    https://msdn.microsoft.com/ja-jp/library/bhczd18c.aspx

    なので、自作クラスでは以下の様に記述することもできました。
    ※今回はForm1上のbutton1ボタンを押したときに GetDistributionListMembers を
     呼び出すようにしました。

    01|using System;
    02|using System.Collections.Generic;
    03|using System.ComponentModel;
    04|using System.Data;
    05|using System.Drawing;
    06|using System.Linq;
    07|using System.Text;
    08|using System.Threading.Tasks;
    09|using System.Windows.Forms;
    10|using Outlook = Microsoft.Office.Interop.Outlook; // add
    11|
    12|namespace OutlookAddIn1C2
    13|{
    14|    public partial class Form1 : Form
    15|    {
    16|        private void button1_Click(object sender, EventArgs e)
    17|        {
    18|            GetDistributionListMembers();
    19|        }
    20|
    21|        public void GetDistributionListMembers()
    22|        {
    23|            Outlook.Application Application = Globals.ThisAddIn.Application; // 追加した箇所
    24|            Outlook.SelectNamesDialog snd = Application.Session.GetSelectNamesDialog();
    25|            Outlook.AddressLists addrLists = Application.Session.AddressLists;

    本当は関連していくつも質問したいのですが、当初の問題は解決しましたので、
    クローズいたします。
    この返信において、私の記述には間違えていることもあると思うのですが、その時は
    ほかの方に誤解を与えないように大変恐縮ですが、訂正いただくと助かります。

    2017年3月9日 8:09