C# 动态属性分配引发RuntimeBinderException

C# 动态属性分配引发RuntimeBinderException,c#,dynamic,C#,Dynamic,我收到一个带有消息的RuntimeBinderException 无法将类型“object”隐式转换为“MyNamespace.SomeEnum?”。存在显式转换(是否缺少强制转换?) 以下代码生成该错误: public enum SomeEnum { Val1 } public class Example { public SomeEnum? EnumMember { get; set; } } public static class Program { stati

我收到一个带有消息的
RuntimeBinderException

无法将类型“object”隐式转换为“MyNamespace.SomeEnum?”。存在显式转换(是否缺少强制转换?)

以下代码生成该错误:

public enum SomeEnum
{
    Val1
}

public class Example
{
    public SomeEnum? EnumMember { get; set; }
}

public static class Program
{
    static void Main()
    {
        dynamic example = new Example();

        // Works without issue
        example.EnumMember = (dynamic)Enum.Parse(typeof(SomeEnum), "Val1");

        // Works without issue
        example.EnumMember = Enum.Parse(example.EnumMember.GetType(), "Val1");

        // Throws the aforementioned RuntimeBinderException
        example.EnumMember = Enum.Parse(typeof(SomeEnum), "Val1");
    }
}

为什么前两行可以工作(都是返回类型动态),但第三行抛出异常(当返回类型为object时)?我的印象是,当分配给dynamic时,绑定是使用右侧的实际运行时类型执行的。有人能告诉我为什么第三行不能像写的那样运行吗?

您仍然需要对第三行进行隐式转换

example.EnumMember = (SomeEnum) Enum.Parse(typeof(SomeEnum), "Val1");
编辑

仍然需要隐式转换的原因是
Enum.Parse
返回一个对象。请参阅以下文档


您仍然需要对第三行进行隐式转换

example.EnumMember = (SomeEnum) Enum.Parse(typeof(SomeEnum), "Val1");
编辑

仍然需要隐式转换的原因是
Enum.Parse
返回一个对象。请参阅以下文档


前两行的
=
运算符的RHS上表达式的编译时类型是
动态的
。在第一种情况下,这是因为您强制转换为
动态
,而在第二种情况下,这是因为您在其中一个参数中使用了动态值

在第三种情况下,表达式的编译时类型是
object
。因此,您尝试执行以下等效操作:

object x = Enum.Parse(typeof(SomeEnum), "Val1");
example.EnumMember = x;
这不起作用,因为没有从
对象
SomeEnum?
的隐式转换,这是编译器在执行时试图找到的

请注意,可空性部分在这里并不相关——事实上它也是一个枚举。只是赋值操作符是动态绑定的,但是使用RHS的编译时。下面是一个类似但更简单的示例:

class Test
{
    public int Foo { get; set; }

    static void Main()
    {
        dynamic example = new Test();

        example.Foo = 10; // Fine

        object o = 10;
        example.Foo = o; // Bang
    }
}
如果您希望编译器使用返回值的实际类型而不是编译时类型动态处理赋值,则使用
动态
正是您想要做的-转换为动态,或使用:

dynamic value = ...;
target.SomeProperty = value;

前两行的
=
运算符的RHS上表达式的编译时类型为
动态
。在第一种情况下,这是因为您强制转换为
动态
,而在第二种情况下,这是因为您在其中一个参数中使用了动态值

在第三种情况下,表达式的编译时类型是
object
。因此,您尝试执行以下等效操作:

object x = Enum.Parse(typeof(SomeEnum), "Val1");
example.EnumMember = x;
这不起作用,因为没有从
对象
SomeEnum?
的隐式转换,这是编译器在执行时试图找到的

请注意,可空性部分在这里并不相关——事实上它也是一个枚举。只是赋值操作符是动态绑定的,但是使用RHS的编译时。下面是一个类似但更简单的示例:

class Test
{
    public int Foo { get; set; }

    static void Main()
    {
        dynamic example = new Test();

        example.Foo = 10; // Fine

        object o = 10;
        example.Foo = o; // Bang
    }
}
如果您希望编译器使用返回值的实际类型而不是编译时类型动态处理赋值,则使用
动态
正是您想要做的-转换为动态,或使用:

dynamic value = ...;
target.SomeProperty = value;

OP知道这一点,并问“为什么?”问题是,在实际代码中,我不知道类型
SomeEnum
,因此无法显式添加该强制转换。如果您知道其他方法,而不必强制转换到
dynamic
SomeEnum
以使分配生效,我很想学习它。OP知道这一点,并询问“为什么?”问题是,在实际代码中,我不知道类型
SomeEnum
,因此我无法明确添加该强制转换。如果您知道其他一些方法,而不必强制转换到
dynamic
SomeEnum
以使赋值生效,我很想了解它。第二个示例
对象中RHS的编译时类型不是
dynamic
?这就是我被卡住的地方-第二个和第三个调用似乎是相同的,除了编译时解析
typeof
@DStanley:Nope之外,因为调用是动态绑定的,因为第一个参数使用
示例
。请尝试将结果赋给
var
,并将鼠标悬停在声明上,您将看到:)@DStanley No,因为example.EnumMember.GetType()返回
dynamic
,因此根据定义,Enum.Parse表达式还必须返回type
dynamic
。啊。这就是区别。知道了。谢谢。第二个示例中RHS的编译时类型不是
对象
,不是
动态
?这就是我被卡住的地方-第二个和第三个调用似乎是相同的,除了编译时解析
typeof
@DStanley:Nope之外,因为调用是动态绑定的,因为第一个参数使用
示例
。请尝试将结果赋给
var
,并将鼠标悬停在声明上,您将看到:)@DStanley No,因为example.EnumMember.GetType()返回
dynamic
,因此根据定义,Enum.Parse表达式还必须返回type
dynamic
。啊。这就是区别。知道了。谢谢