C# 将not nullable转换为nullable属性后重新编译

C# 将not nullable转换为nullable属性后重新编译,c#,C#,我有一个项目,在MyRequest课程中涉及以下部分 public int TestName {get; set;} 它被另一个项目使用-我们称之为Foolike var request = new MyRequest { TestName = mainCustomerNumber, }; 过了一会儿,我将TestName更改为可为null的类型,即public int?TestName{get;set

我有一个项目,在
MyRequest
课程中涉及以下部分

public int TestName {get; set;}
它被另一个项目使用-我们称之为
Foo
like

var request = new MyRequest
              {
               TestName = mainCustomerNumber,
              };  
过了一会儿,我将
TestName
更改为可为null的类型,即
public int?TestName{get;set;}
并编译了涉及
MyRequest
类的项目。我是否也需要重新编译project
Foo
你能告诉我们原因吗?你有两个项目。 “一”具有MyRequest类 “另一个”有Foo

并更改MyRequest类中TestName的类型

我想这是你的问题


如果您直接从Foo访问MyReueset,我认为不需要重新编译。

int
int?
是两种完全不同的值类型。一个是
System.Int32
,另一个是
System.Nullable
。在源代码中只有一个
的差异,这一事实只会掩盖这种差异

请注意,如果在引用类型(C#8.0)(如
string?
)上使用了null/non-null选项,则可能不需要重新编译,因为这只是一个建议(编译器只需在
string
类型上添加装饰属性)

请参见右侧窗格中的

在低级别(IL语言),
int
int?
的处理方式非常不同

这:

翻译为:

.field public valuetype [System.Private.CoreLib]System.Nullable`1<int32> Int1
.field public int32 Int2

// Methods
.method public hidebysig 
    instance void SetInt1 () cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 13 (0xd)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: ldc.i4.5
    IL_0002: newobj instance void valuetype [System.Private.CoreLib]System.Nullable`1<int32>::.ctor(!0)
    IL_0007: stfld valuetype [System.Private.CoreLib]System.Nullable`1<int32> C::Int1
    IL_000c: ret
} // end of method C::SetInt1

.method public hidebysig 
    instance void SetInt2 () cil managed 
{
    // Method begins at RVA 0x205e
    // Code size 8 (0x8)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: ldc.i4.5
    IL_0002: stfld int32 C::Int2
    IL_0007: ret
} // end of method C::SetInt2

我实际上是在模拟它。为了憎恨
Foo
的人,让我们把这个类命名为
Runner
,它将一个库引用为.dll,其名称是
Test
Test
类只涉及
publictinttestname{get;set;}

让我们扩展一下

//public int TestName {get; set;} equals to roughly
private int TestName ;

public void set_TestName(int value)
{
    TestName = value;
}

public int get_TestName()
{
    TestName = value;
}
当我想编译
Runner
类时,它被转换为

Test x = new Test();
x.set_TestName(5);
Console.WriteLine(x.get_TestName());
Console.ReadKey();
现在,让我们将
Test
类中的getter setter更改为
public int?TestName{get;set;}
并展开它

//public int? TestName {get; set;} equals to roughly
private int? TestName ;

public void set_TestName(int? value)
{
    TestName = value;
}

public int? get_TestName()
{
    TestName = value;
}
并编译
Test
类。但不是
Runner
类。
Runner
类生成以下消息

Unhandled Exception: System.MissingMethodException: 
Method not found: 'Void NameSpaceOfTest.Test.set_TestName(Int32)'.  <-----
   at NameSpaceOfRunner.Runner.Main(String[] args)
未处理的异常:System.MissingMethodException:

找不到方法:“Void NameSpaceOfTest.Test.set_TestName(Int32)”。是的,你知道。你改变了合同。@MJ Wills你能详细说明你的答案吗?但是仍然有一个整数值被分配给了。不是真的。你改变了合同。所以,它需要重新编译。我是说,如果你愿意,你可以自己试试。编译
MyRequest
,但不要编译
Foo
,然后尝试运行该软件。看看会发生什么。@mjwills我也会犯同样的错误。我完全明白我需要它重新编译。但是为什么呢?@mjwills我想我已经找到了答案。->那个
TestName=mainCustomerNumber
只是
TestName=new Nullable(mainCustomerNumber)
int?
案例中的语法糖。Foo中的代码看起来是一样的,但事实并非如此。@Heinzi根据IL代码判断,我会说是的。
//public int? TestName {get; set;} equals to roughly
private int? TestName ;

public void set_TestName(int? value)
{
    TestName = value;
}

public int? get_TestName()
{
    TestName = value;
}
Unhandled Exception: System.MissingMethodException: 
Method not found: 'Void NameSpaceOfTest.Test.set_TestName(Int32)'.  <-----
   at NameSpaceOfRunner.Runner.Main(String[] args)