トップ回答者
c#でのusingディレクティブの適用範囲が分からない

質問
-
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です。何か基本知識が足りないのだと思うのですが、それが何であるか
いろいろと調べてみましたが、さっぱりわかりません。何を勘違いしていて、どんな基礎知識が足りないのか、
教えていただきますよう、お願いいたします。
回答
-
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
- 編集済み kenjinoteMVP 2017年3月7日 3:35
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年3月8日 0:20
- 回答としてマーク よーすけ 2017年3月9日 8:03
-
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プロパティ経由でアクセスできると思います。
- 編集済み tmori3y2 2017年3月7日 15:32
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年3月8日 0:20
- 回答としてマーク よーすけ 2017年3月9日 8:02
すべての返信
-
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
- 編集済み kenjinoteMVP 2017年3月7日 3:35
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年3月8日 0:20
- 回答としてマーク よーすけ 2017年3月9日 8:03
-
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プロパティ経由でアクセスできると思います。
- 編集済み tmori3y2 2017年3月7日 15:32
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年3月8日 0:20
- 回答としてマーク よーすけ 2017年3月9日 8:02
-
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;本当は関連していくつも質問したいのですが、当初の問題は解決しましたので、
クローズいたします。
この返信において、私の記述には間違えていることもあると思うのですが、その時は
ほかの方に誤解を与えないように大変恐縮ですが、訂正いただくと助かります。