7

いくつかのリファクタリング後に興味深いランタイムの問題に遭遇し、次の状況に陥りました。

親インターフェイスから継承されたインターフェイスのメソッドに動的オブジェクトからプロパティを渡す場合、ランタイム バインダーはメソッドを見つけることができません。

失敗と成功の両方を示すテストを次に示します (親インターフェイス タイプでメソッドを直接呼び出す場合)

using System.Dynamic;
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Test.Utility
{
    public interface IEcho
    {
        string EchoString(string input);
    }

    public interface IInheritEcho : IEcho
    { }

    public class EchoClass : IInheritEcho
    {
        public string EchoString(string input)
        {
            return input;
        }
    }

    [TestClass]
    public class RuntimeBinderTest
    {
        [TestMethod]
        public void RuntimeBinder_should_work_when_dynamic_parameters_are_passed_to_method_from_inherited_interface()
        {
            //Arrange
            dynamic dynObject = new ExpandoObject();
            dynObject.Foo = "Bar";
            IInheritEcho echomore = new EchoClass();

            string echo = null;
            string exceptionMessage = null;

            //Act
            try
            {
                echo = echomore.EchoString(dynObject.Foo);
            }
            catch (RuntimeBinderException e)
            {
                exceptionMessage = e.Message;
            }

            //Assert
            Assert.AreEqual(echo, dynObject.Foo, false, exceptionMessage);
        }

        [TestMethod]
        public void RuntimeBinder_should_work_when_dynamic_parameters_are_passed_to_method_from_noninherited_interface()
        {
            //Arrange
            dynamic dynObject = new ExpandoObject();
            dynObject.Foo = "Bar";
            IEcho echomore = new EchoClass();

            string echo = null;
            string exceptionMessage = null;

            //Act
            try
            {
                echo = echomore.EchoString(dynObject.Foo);
            }
            catch (RuntimeBinderException e)
            {
                exceptionMessage = e.Message;
            }

            //Assert
            Assert.AreEqual(echo, dynObject.Foo, false, exceptionMessage);
        }
    }
}

テスト #1 失敗: Assert.AreEqual が失敗しました。予想:<(null)>。実際:。「Test.Utility.IInheritEcho」に「EchoString」の定義が含まれていません

テスト #2 成功。

私の質問は、最初のテストに合格する必要があるという私の仮定が正しいかどうか、またはフレームワークにそうでない根本的な理由があるかどうかです。

パラメーターを渡すときにパラメーターをキャストするか、パラメーターを渡す前に変数に割り当てることで問題を解決できることはわかっています。継承されたインターフェイスが原因で RuntimeBinder が失敗する理由についてもっと知りたいです...

4

2 に答える 2

4

あなたの状況は、MicrosoftConnectで文書化されたバグです

于 2012-05-10T11:03:58.297 に答える
2

これは良い質問です。

コンパイル時に式の型を取得しているように見えIInheritEchoますが、動的に呼び出すメソッドを探すときに、継承されたインターフェイスのメンバーを深く検索していません。

そして理想的には、dynamic式の C# ランタイム バインダーは C# コンパイラと同じように動作する必要がありIEchoますIInheritEcho

最初のテストでこれを行うことにより、仮説 (つまり、静的型付けであるという仮説) をテストできます。

echo = ((dynamic)echomore).EchoString(dynObject.Foo);

早速 - テストに合格しました。

したがって、問題は動的バインダーがメソッドを見つけられないことではありません。メンバーが動的に呼び出されているインスタンスがインターフェイスとして静的に型指定されている場合、継承されたインターフェイスは参照されません。

私の意見では、この動作は正しくありません。

エリック・リッパートをお願いします...優しくしてください...

于 2012-05-10T10:21:20.867 に答える