C#と諸々

C#がメインで他もまぁ諸々なブログです
おかしなこと書いてたら指摘してくれると嬉しいです(´・∀・`)
つーかコメント欲しい(´・ω・`)

2006/10/20 01:49
MSDNに記載されている、Delegate.DynamicInvokeメソッドの例外に関する情報が間違ってる。
MSDNには以下のように記載されている。


[ MemberAccessException ]
呼び出し元には、(たとえば、メソッドがプライベート メソッドの場合に) デリゲートが表すメソッドへのアクセス権がありません。 または args にリストされているパラメータの数、順序、または型が無効です。

[ TargetException ]
デリゲートが表すメソッドがインスタンス メソッドであり、対象オブジェクトが null 参照 (Visual Basic では Nothing) です。 または デリゲートが表すメソッドが、そのメソッドをサポートしないオブジェクトまたはクラスに対して呼び出されています。

[ TargetInvocationException ]
カプセル化されたメソッドの 1 つが例外をスローします。


しかし、TargetInvocationException以外の例外&説明は、実際と全く異なる。

第一に、デリゲートが表すメソッドがプライベートメソッドだろうが、そのメソッドがプライベートメソッドを呼び出していようが、例外なんて発生しない。また、デリゲートが表すメソッドの要求するアクセス許可が呼び出し元になくて、System.Security.SecurityExceptionがスローされる場合も、MemberAccessExceptionなどスローされず、 ( SecurityExceptionをラップした ) TargetInvocationExceptionがスローされる。

第二に、argsにリストされているパラメータの数、順序、型が無効な場合でも、MemberAccessExceptionはスローされない。パラメータ の数が不正な場合はTargetParameterCountExceptionがスローされ、順序や型が向こうな場合は ArgumentExceptionがスローされる。

第三に、 「 デリゲートが表すメソッドがインスタンス メソッドであり、対象オブジェクトがnull参照 」 なんて状況はありない。 「 対象オブジェクトがnull参照 」 というのは、対象オブジェクトがGCに回収されている状況を指しているのだろうが、デリゲートが存在する限り対象オブジェクトがGCに回収されることはない。デリゲートのTargetプロパティにしっかりと対象オブジェクトの"強い"参照が保持されているから。

第四に、 「 デリゲートが表すメソッドが、そのメソッドをサポートしないオブジェクトまたはクラスに対して呼び出されています。  」 なんて状況もありえない。
まず、以下のように、デリゲートオブジェクトを普通に作成した場合、当然、メソッドとオブジェクトは正しく結びつく。
public delegate void SimpleMethod();

class Class1
{
    public Class1()
    {
    }

    public void Method1()
    {
        Console.WriteLine("Method1 was called.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Class1 obj = new Class1();
        Delegate objMethod1 = (SimpleMethod)obj.Method1;
        objMethod1.DynamicInvoke();
        Console.ReadLine();
    }
}

また、リフレクションを使って作成したとしても、無関係のオブジェクトと関連付けて作成することは不可能である。
public delegate void SimpleMethod();

class Class1
{
    public Class1()
    {
    }

    private void Method1()
    {
        Console.WriteLine("Method1 was called.");
    }
}

class Program
{
    static void Main(string args)
    {
        Assembly thisAssembly = Assembly.GetExecutingAssembly();
        Type class1 = thisAssembly.GetType("Class1");
        MemberInfo[] class1Member = class1.GetMember("Method1", MemberTypes.Method, BindingFlags.Instance | BindingFlags.NonPublic);
        MethodInfo class1Method1Info = class1Member[0] as MethodInfo;
        // 以下のコードでは、実行時に例外がスローされる。
        // Delegate class1Method = Delegate.CreateDelegate(typeof(SimpleMethod), new Object(), class1Method1Info);
        Delegate class1Method = Delegate.CreateDelegate(typeof(SimpleMethod), new Class1(), class1Method1Info);
        class1Method.DynamicInvoke();
        Console.ReadLine();
    }
}

( ついでに、対象メソッドの可視性はプライベートにしてある。 )


で、結局のところ、Delegate.DynamicInvokeメソッドの例外は、正しくは以下のようになる。

[ System.ArgumentException ]
args にリストされているパラメータの順序、または型が無効である場合にスローされる。

[ System.Reflection.TargetParameterCountException ]
args にリストされているパラメータの数が、必要なパラメータ数と異なる場合にスローされる。

[ System.Reflection.TargetInvocationException ]
カプセル化されたメソッドの 1 つが例外をスローする場合にスローされる。
・・・最近ネタがないから、たいしたことじゃないのに長々と書いてみたり (;´∀`)
タグ: C# .NET


MSDNフォーラムにフィードバックしておきました。
http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=853912&SiteID=7

2006.10.25 00:10 URL | よこけん #- [ 編集 ]












トラックバックURL↓
http://csharper.blog57.fc2.com/tb.php/37-e525ecaa