在继承类型中使用C#dynamic进行方法调用

时间:2018-01-19 09:15:50

标签: c# dynamic

我在尝试扩展基类时注意到了一个意外的行为。以下是此问题的示例:

public class Program
{
    static void Main(string[] args)
    {
        var test = new CoolProgram();
        test.Start();
    }

    private void Start()
    {
        var arr = new object[]
        {
            1, // int
            1L, // long
            "Hello World" // string
        };

        foreach (var dyn in arr.Cast<dynamic>())
        {
            DoSomething(dyn);
        }

        Console.ReadKey();
    }

    protected virtual void DoSomething(int i)
    {
        Console.WriteLine("Int:" + i);
    }

    protected virtual void DoSomething(string str)
    {
        Console.WriteLine("Str:" + str);
    }
}

Program定义了两个由DoSomethingint参数重载的方法stringStart方法创建一个对象which contains boxed values. After the definition, the elements will be iterated with casted dynamic`数组。这到目前为止工作正常(没有长值)。

如果我创建一个额外的继承类CoolProgram并为long的类型添加另一个方法,程序将抛出RuntimeBinderException并告诉我最佳重载是{{1} }。 DoSomething(int)的方法未执行。

CoolProgram

有人可以解释这种行为或有解决方案吗?

2 个答案:

答案 0 :(得分:2)

您的示例可以进一步简化:

static void Main(string[] args)
{
    Program test = new CoolProgram();
    dynamic i = 1L;

    test.DoSomething(i);
    //test.Start();
}

问题是,就Start()方法而言,this的类型为Program。为virtual添加DoSomething()重载意味着Start()方法的上下文中没有任何内容。

同样在我上面的简化示例中。编译时类型testProgram,就像this中的Start()类型为Program一样。因此,DoSomething(long)重载在该上下文中不可见,并且无法调用。

如果希望它可见,则需要将其添加到基类,或确保用于调用DoSomething()的引用静态类型为CoolProgram。请注意,由于该方法在protected中声明为CoolProgram,因此如果您想要将引用的静态类型更改为{{1},那么您还必须更改可访问性。 }。

最后,如果你真的想要完全动态的类型解析,你可以:

CoolProgram

如上所述,上述内容当然需要private void Start() { dynamic this2 = this; var arr = new object[] { 1, // int 1L, // long "Hello World" // string }; foreach (var dyn in arr.Cast<dynamic>()) { this2.DoSomething(dyn); } Console.ReadKey(); } DoSomething(long)

答案 1 :(得分:0)

1)第一个问题是访问修饰符受保护,因为您无法使用Long类型作为参数访问重载方法。我把它改成了内部现在可以访问。

2)第二个问题是你正在创建子类CoolProgram对象但你要调用父类DoSomething方法你应该使用test.DoSomething(dyn);并使子类对象全局化以在Start方法中访问它。

public class Program
{
static CoolProgram test;
static void Main(string[] args)
{
    test = new CoolProgram();
    test.Start();
}

private void Start()
{
    var arr = new object[]
    {
        1, // int
        1L, // long
        "Hello World" // string
    };
    //test.DoSomething(21474836470);
    foreach (var dyn in arr.Cast<dynamic>())
    {
        test.DoSomething(dyn);
    }

    Console.ReadKey();
}

protected virtual void DoSomething(int i)
{
    Console.WriteLine("Int:" + i);
}

protected virtual void DoSomething(string str)
{
    Console.WriteLine("Str:" + str);
}
}
// from here child class
public class CoolProgram : Program
{
  protected override void DoSomething(int i)
  {
    // This works
    Console.WriteLine("Cool Int: " + i);
    base.DoSomething(i);
 }

 protected override void DoSomething(string str)
 {
    // This works
    Console.WriteLine("Cool Str: " + str);
 }

 internal virtual void DoSomething(long i)
 {
    // This is a new method for long
    Console.WriteLine("Long Int:" + i);
 }

 }