2020-08-26T21:10:25の更新内容
programming/netfx/fcl/System.Runtime.InteropServices.CoClassAttribute/index.wiki.txt
current | previous | |
---|---|---|
1,341 | 0,0 | |
+ |
%smdncms%(set-metadata,title,System.Runtime.InteropServices.CoClassAttribute) |
|
+ |
%smdncms%(set-metadata,alternative-document-versions,codelang=cs,codelang=vb) |
|
+ | ||
+ |
*CoClass属性 |
|
+ |
&msdn(netfx,type,System.Runtime.InteropServices.CoClassAttribute){CoClassAttribute};の本来の目的であるCOM interopはさておき、CoClass属性を使うと、次の例のように見かけ上インターフェイスを直接``new``する、インターフェイスに対して''デフォルト実装クラス''を定義するようなことができる。 |
|
+ | ||
+ |
#tabpage(codelang=cs,container-title=CoClassAttributeを使ってインターフェイスのデフォルト実装クラスを定義する) |
|
+ |
#code{{ |
|
+ |
using System; |
|
+ |
using System.Runtime.InteropServices; |
|
+ | ||
+ |
[CoClass(typeof(C))] // クラスCをインターフェイスIのコクラスとして定義する |
|
+ |
[ComImport] |
|
+ |
[Guid("2964ca28-75b5-4eba-9472-e2aa977b5cf3")] |
|
+ |
interface I { |
|
+ |
void M(); |
|
+ |
} |
|
+ | ||
+ |
// インターフェイスIを実装するクラス |
|
+ |
class C : I { |
|
+ |
public void M() => Console.WriteLine("Hello, world!"); |
|
+ |
} |
|
+ | ||
+ |
public static class Sample { |
|
+ |
static void Main() |
|
+ |
{ |
|
+ |
// インターフェイスIに対してnewする |
|
+ |
var i = new I(); |
|
+ | ||
+ |
// 作成したインスタンスのメソッドMを呼び出す |
|
+ |
i.M(); |
|
+ | ||
+ |
// インスタンスiの型情報を取得する (クラスCの型情報が取得される) |
|
+ |
Console.WriteLine($"type of {nameof(i)} is {i.GetType()}"); |
|
+ |
} |
|
+ |
} |
|
+ |
}} |
|
+ |
#tabpage(codelang=vb) |
|
+ |
#code{{ |
|
+ |
Imports System |
|
+ |
Imports System.Runtime.InteropServices |
|
+ | ||
+ |
< |
|
+ |
CoClass(GetType(C)), ' クラスCをインターフェイスIのコクラスとして定義する |
|
+ |
ComImport, |
|
+ |
Guid("2964ca28-75b5-4eba-9472-e2aa977b5cf3") |
|
+ |
> |
|
+ |
Interface I |
|
+ |
Sub M() |
|
+ |
End Interface |
|
+ | ||
+ |
' インターフェイスIを実装するクラス |
|
+ |
Class C |
|
+ |
Implements I |
|
+ | ||
+ |
Public Sub M() Implements I.M |
|
+ |
Console.WriteLine("Hello, world!") |
|
+ |
End Sub |
|
+ |
End Class |
|
+ | ||
+ |
Public Module Sample |
|
+ |
Sub Main() |
|
+ |
' インターフェイスIに対してNewする |
|
+ |
Dim i As New I() |
|
+ | ||
+ |
' 作成したインスタンスのメソッドMを呼び出す |
|
+ |
i.M() |
|
+ | ||
+ |
' インスタンスiの型情報を取得する (クラスCの型情報が取得される) |
|
+ |
Console.WriteLine($"type of {NameOf(i)} is {i.GetType()}") |
|
+ |
End Sub |
|
+ |
End Module |
|
+ |
}} |
|
+ |
#tabpage-end |
|
+ | ||
+ |
#prompt(実行結果){{ |
|
+ |
Hello, world! |
|
+ |
type of i is C |
|
+ |
}} |
|
+ | ||
+ |
インターフェイス``I``に対する``new``は、コンパイル時において、CoClass属性で指定されたコクラス``C``に対する``new``に置き換えられる。 |
|
+ | ||
+ | ||
+ | ||
+ |
シグニチャがマッチする、かつアクセス可能なコンストラクタが存在する場合は、引数付きで``new``することもできる。 引数リストと一致するアクセス可能なコンストラクタがなければ''コンパイルエラー''となる(実行時例外ではない)。 |
|
+ | ||
+ |
#tabpage(codelang=cs,container-title=CoClassAttributeで定義したデフォルト実装クラスと引数付きのコンストラクタ) |
|
+ |
#code{{ |
|
+ |
using System; |
|
+ |
using System.Runtime.InteropServices; |
|
+ | ||
+ |
[CoClass(typeof(C))] |
|
+ |
[ComImport] |
|
+ |
[Guid("2964ca28-75b5-4eba-9472-e2aa977b5cf3")] |
|
+ |
interface I { |
|
+ |
void M(); |
|
+ |
} |
|
+ | ||
+ |
class C : I { |
|
+ |
// 引数を取るコンストラクタ |
|
+ |
public C(int x, string y, object z) => Console.WriteLine($"x = {x}, y = {y}, z = {z}"); |
|
+ | ||
+ |
public void M() => Console.WriteLine("Hello, world!"); |
|
+ |
} |
|
+ | ||
+ |
public static class Sample { |
|
+ |
static void Main() |
|
+ |
{ |
|
+ |
new I(42, "foo", "bar"); |
|
+ |
} |
|
+ |
} |
|
+ | ||
+ |
}} |
|
+ |
#tabpage(codelang=vb) |
|
+ |
#code{{ |
|
+ |
Imports System |
|
+ |
Imports System.Runtime.InteropServices |
|
+ | ||
+ |
< |
|
+ |
CoClass(GetType(C)), |
|
+ |
ComImport, |
|
+ |
Guid("2964ca28-75b5-4eba-9472-e2aa977b5cf3") |
|
+ |
> |
|
+ |
Interface I |
|
+ |
Sub M() |
|
+ |
End Interface |
|
+ | ||
+ |
Class C |
|
+ |
Implements I |
|
+ | ||
+ |
Public Sub New(ByVal x As Integer, ByVal y As String, ByVal z As Object) |
|
+ |
Console.WriteLine($"x = {x}, y = {y}, z = {z}") |
|
+ |
End Sub |
|
+ | ||
+ |
Public Sub M() Implements I.M |
|
+ |
Console.WriteLine("Hello, world!") |
|
+ |
End Sub |
|
+ |
End Class |
|
+ | ||
+ |
Public Module Sample |
|
+ |
Sub Main() |
|
+ |
Dim i As New I(42, "foo", "bar") |
|
+ |
End Sub |
|
+ |
End Module |
|
+ |
}} |
|
+ |
#tabpage-end |
|
+ | ||
+ |
#prompt(実行結果){{ |
|
+ |
x = 42, y = foo, z = bar |
|
+ |
}} |
|
+ | ||
+ | ||
+ | ||
+ |
アセンブリ境界を跨ぐ場合、コクラスにアクセスできなければ''コンパイルエラー''となる(実行時例外ではない)。 このため、ライブラリにてインターフェイスとデフォルト実装(CoClass属性)のみを公開しつつ、デフォルト実装クラスは非公開とする、といったことはできない。 |
|
+ | ||
+ |
#code(cs,ライブラリ側コード){{ |
|
+ |
using System; |
|
+ |
using System.Runtime.InteropServices; |
|
+ | ||
+ |
[assembly: System.Reflection.AssemblyTitle("Library")] |
|
+ | ||
+ |
namespace Library { |
|
+ |
// コクラスを指定したpublicなインターフェイス |
|
+ |
[CoClass(typeof(C))] |
|
+ |
[ComImport] |
|
+ |
[Guid("2964ca28-75b5-4eba-9472-e2aa977b5cf3")] |
|
+ |
public interface I { |
|
+ |
void M(); |
|
+ |
} |
|
+ | ||
+ |
// コクラス(internalなクラス) |
|
+ |
internal class C : I { |
|
+ |
public void M() => Console.WriteLine("Hello, world!"); |
|
+ |
} |
|
+ |
} |
|
+ |
}} |
|
+ | ||
+ |
#code(cs,アプリケーション側コード){{ |
|
+ |
// <ProjectReference Include="Library.csproj" /> |
|
+ | ||
+ |
using System; |
|
+ | ||
+ |
[assembly: System.Reflection.AssemblyTitle("Application")] |
|
+ | ||
+ |
namespace Application { |
|
+ |
public static class Sample { |
|
+ |
static void Main() |
|
+ |
{ |
|
+ |
var i = new Library.I(); // error CS0122: 'C.C()' はアクセスできない保護レベルになっています |
|
+ | ||
+ |
i.M(); |
|
+ |
} |
|
+ |
} |
|
+ |
} |
|
+ |
}} |
|
+ | ||
+ | ||
+ |
**ComImport属性とGuid属性 |
|
+ |
C#でCoClass属性をインターフェイスに付与する場合、&msdn(netfx,type,System.Runtime.InteropServices.ComImportAttribute){ComImport属性};と&msdn(netfx,type,System.Runtime.InteropServices.GuidAttribute){Guid属性};も同時に付与する必要がある。 Guid属性で指定するGUIDは適当でよい(COM importを目的としないのであれば)。 |
|
+ | ||
+ |
#code(cs,C#では、CoClass属性はComImport属性とGuid属性とともに指定する必要がある){{ |
|
+ |
[CoClass(typeof(C))] |
|
+ |
/*[ComImport]*/ // warning CS0684: 'I' インターフェイスは、'CoClassAttribute' でマークされていますが、'ComImportAttribute' ではマークされていません。 |
|
+ |
/*[Guid("2964ca28-75b5-4eba-9472-e2aa977b5cf3")]*/ // error CS0596: Guid 属性は ComImport 属性を使って指定する必要があります。 |
|
+ |
interface I { |
|
+ |
void M(); |
|
+ |
} |
|
+ |
}} |
|
+ | ||
+ | ||
+ | ||
+ |
VBでCoClass属性をインターフェイスに付与する場合は、ComImport属性とGuid属性は必ずしも付与する必要がなく、コンパイル時に自動的に付与されるわけでもない模様。 |
|
+ | ||
+ |
#code(vb,VBでは、CoClass属性は必ずしもComImport属性とGuid属性を伴っていなくてもよい){{ |
|
+ |
Imports System |
|
+ |
Imports System.Runtime.InteropServices |
|
+ |
Imports System.Reflection |
|
+ | ||
+ |
<CoClass(GetType(C))> ' ComImport属性とGuid属性がなくてもコンパイルできる |
|
+ |
Interface I |
|
+ |
Sub M() |
|
+ |
End Interface |
|
+ | ||
+ |
Class C |
|
+ |
Implements I |
|
+ | ||
+ |
Public Sub M() Implements I.M |
|
+ |
Console.WriteLine("Hello, world!") |
|
+ |
End Sub |
|
+ |
End Class |
|
+ | ||
+ |
Public Module Sample |
|
+ |
Sub Main() |
|
+ |
Dim i As New I() |
|
+ | ||
+ |
Console.WriteLine($"Guid = {i.GetType().GetCustomAttribute(Of GuidAttribute)()}") |
|
+ |
Console.WriteLine($"ComImport = {i.GetType().GetCustomAttribute(Of ComImportAttribute)()}") |
|
+ |
End Sub |
|
+ |
End Module |
|
+ |
}} |
|
+ | ||
+ |
#prompt(実行結果){{ |
|
+ |
Guid = |
|
+ |
ComImport = |
|
+ |
}} |
|
+ | ||
+ | ||
+ |
**インターフェイスメソッドのデフォルト実装との比較 |
|
+ | ||
+ |
#column(layout=fixed) |
|
+ |
#code(cs,CoClassによるデフォルト実装クラス){{ |
|
+ |
using System; |
|
+ |
using System.Runtime.InteropServices; |
|
+ | ||
+ |
// デフォルト実装クラスを持つインターフェイス |
|
+ |
[CoClass(typeof(C))] |
|
+ |
[ComImport] |
|
+ |
[Guid("2964ca28-75b5-4eba-9472-e2aa977b5cf3")] |
|
+ |
interface I { |
|
+ |
void M(); |
|
+ |
} |
|
+ | ||
+ |
// インターフェイスIを実装するクラス |
|
+ |
class C : I { |
|
+ |
public void M() => Console.WriteLine("Hello, world!"); |
|
+ |
} |
|
+ | ||
+ |
public static class Sample { |
|
+ |
static void Main() |
|
+ |
{ |
|
+ |
// インターフェイスIに対してnewする |
|
+ |
var i = new I(); |
|
+ | ||
+ |
// 作成したインスタンスのメソッドMを呼び出す |
|
+ |
i.M(); |
|
+ | ||
+ |
// インスタンスiの型情報を取得する |
|
+ |
Console.WriteLine($"type of {nameof(i)} is {i.GetType()}"); |
|
+ |
} |
|
+ |
} |
|
+ |
}} |
|
+ | ||
+ |
#prompt(実行結果){{ |
|
+ |
Hello, world! |
|
+ |
type of i is C |
|
+ |
}} |
|
+ |
#column |
|
+ |
#code(cs,インターフェイスメソッドのデフォルト実装){{ |
|
+ |
using System; |
|
+ | ||
+ | ||
+ |
// メソッドのデフォルト実装を持つインターフェイス |
|
+ | ||
+ | ||
+ | ||
+ |
interface I { |
|
+ |
void M() => Console.WriteLine("Hello, world!"); |
|
+ |
} |
|
+ | ||
+ |
// インターフェイスIを実装するクラス |
|
+ |
class C : I { |
|
+ | ||
+ |
} |
|
+ | ||
+ |
public static class Sample { |
|
+ |
static void Main() |
|
+ |
{ |
|
+ |
// クラスCのインスタンスを作成し、インターフェイスIに変換する |
|
+ |
I i = new C(); |
|
+ | ||
+ |
// 作成したインスタンスのメソッドMを呼び出す |
|
+ |
i.M(); |
|
+ | ||
+ |
// インスタンスiの型情報を取得する |
|
+ |
Console.WriteLine($"type of {nameof(i)} is {i.GetType()}"); |
|
+ |
} |
|
+ |
} |
|
+ |
}} |
|
+ | ||
+ |
#prompt(実行結果){{ |
|
+ |
Hello, world! |
|
+ |
type of i is C |
|
+ |
}} |
|
+ |
#column-end |
|
+ | ||
+ | ||
+ |
*参考 |
|
+ |
#relevantdocs(参考) |
|
+ | ||
+ |
-[[C# 9: newキーワードの型推論:https://www.infoq.com/jp/news/2020/07/csharp-9-new/]] |
|
+ |
-[[COM の CoClass について調べた - しばやん雑記:https://blog.shibayan.jp/entry/20080101/1199114777]] |
|
+ | ||
+ |
#relevantdocs-end |
|
+ | ||
+ |
#relevantdocs |
|
+ | ||
+ |
-[[programming/tips/createlnk]] |
|
+ |
-[[programming/tips/axwebbrowser]] |
|
+ | ||
+ |
#relevantdocs-end |
|
+ |