C# 重载属性设置器

C# 重载属性设置器,c#,C#,我在看,这让我很好奇 每当我定义一个具有自动属性的类时 // Example A public class MyObject { public int MyInt { get; set; } } JIT编译器将其转换为类似于以下内容: // Example B public class MyObject { private int _MyInt; public int get_MyInt() { return _MyInt; } public void s

我在看,这让我很好奇

每当我定义一个具有自动属性的类时

// Example A
public class MyObject
{
  public int MyInt { get; set; }
}
JIT编译器将其转换为类似于以下内容:

// Example B
public class MyObject
{
  private int _MyInt;

  public int get_MyInt()
  { 
    return _MyInt;
  }

  public void set_MyInt(int value)
  {
    _MyInt = value;
  }
}
所以你可以假设写下如下内容:

// Example C.1
public class MyObject 
{
  public int MyInt { get; set; }

  public void set_MyInt(string value)
  {
    MyInt = int.Parse(value);
  }
}
或者可能是这样的:

// Example C.2
public class MyObject 
{
  private int _myInt;
  public int MyInt 
  {
    get { return _myInt; }
    set 
    { 
      _myInt = value; 
    }
    set(string) 
    { 
      _myInt = int.Parse(value); 
    }
  }
}
并确保此功能存在时没有编译器错误

// Example D
public void DoSomething(string someIntegerAsAString)
{
  var myObject = new MyObject()
  {
    MyInt = someIntegerAsAString
  };
}
是什么阻止了编译器说出诸如示例D这样的代码,在这里可以推断出所需的结果,并且它可以正常工作,并且是预期的?功能就在那里,如示例B所示


这是否与语言设计者设计语言的工作方式和行为方式背道而驰?

您确实可以这样做

public class MyObject 
{
  public int MyInt { get; set; }

  public void set_MyInt(string value)
  {
    MyInt = int.Parse(value);
  }
}
…尽管将字符串转换为int会带来明显的性能开销

这是行不通的:

public class MyObject 
{
  private int _myInt;
  public int MyInt 
  {
    get { return _myInt; }
    set 
    { 
      _myInt = value; 
    }
    set(string) 
    { 
      _myInt = int.Parse(value); 
    }
  }
}
…因为C#不支持
setter
重载。然而,您可以通过实现类似的功能,但必须在您自己的类型上实现。Integer是一种值类型,因此它本质上是密封的

C#设计器确实给了我们实现隐式类型转换的能力。然而,他们可能不希望它与基元类型一起工作以避免混淆

想象一下这句话:

var myvar = 2;
myvar = "4";

任何看了上面几行的人都会认为我们谈论的是像JavaScript这样的动态语言。在JavaScript中,
myvar
将是第二行的字符串。如果C#支持您所描述的内容,它仍然是一个
int
。一、 例如,您可能会发现它令人困惑。

不是
JIT
为属性生成
get.*
set.*
方法

如果反编译此代码:

public int MyInt { get; set; }
您将得到以下信息:

.property instance int32 MyInt()
{
    .get instance int32 C::get_MyInt()
    .set instance void C::set_MyInt(int32)
} // end of property C::MyInt

.method public hidebysig specialname instance int32 
        get_MyInt() cil managed
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
    // Code size       11 (0xb)
    .maxstack  1
    .locals init (int32 V_0)
    IL_0000:  ldarg.0
    IL_0001:  ldfld      int32 C::'<MyInt>k__BackingField'
    IL_0006:  stloc.0
    IL_0007:  br.s       IL_0009
    IL_0009:  ldloc.0
    IL_000a:  ret
} // end of method C::get_MyInt

.method public hidebysig specialname instance void 
        set_MyInt(int32 'value') cil managed
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  ldarg.1
    IL_0002:  stfld      int32 C::'<MyInt>k__BackingField'
    IL_0007:  ret
} // end of method C::set_MyInt
.property实例int32 MyInt()
{
.get实例int32 C::get_MyInt()
.set实例void C::set_MyInt(int32)
}//属性C::MyInt的结尾
.method公共隐藏实例specialname实例int32
获取受管理的\u MyInt()cil
{
.custom instance void[mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()=(01 00)
//代码大小11(0xb)
.maxstack 1
.locals init(int32 V_0)
IL_0000:ldarg.0
IL_0001:ldfld int32 C::'k__BackingField'
IL_0006:stloc.0
IL_0007:br.s IL_0009
IL_0009:ldloc.0
IL_000a:ret
}//方法C的结尾::get\u MyInt
.method public Hidebysing specialname实例无效
设置\u MyInt(int32“值”)cil管理
{
.custom instance void[mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()=(01 00)
//代码大小8(0x8)
.maxstack 8
IL_0000:ldarg.0
IL_0001:ldarg.1
IL_0002:stfld int32 C::“k_BackingField”
IL_0007:ret
}//方法C的结尾::set_MyInt
如果你看,你会发现它有一个和一个。“方法”,而不是“方法”


这与框架有关,尽管我不知道任何一种语言的属性有多个getter或setter。你懂这样的语言吗?

在第一个例子中,没有什么能阻止你。编译错误正在第二时间阻止您。不支持重载的属性设置程序。你不妨使用一种方法。可能还有一些奇怪的方法可以滥用它,那么为什么要在很少使用的东西上浪费时间、精力和金钱呢?事实上,你可以用动态绑定来实现方法重载,用自动实现的属性是不可能的,但有时它可以帮助复制我意识到这一点。但我要说的关键是编译器识别这个功能。我想我需要更多的信息(从高层次上)来解释为什么编译器不支持这样的东西,而在我看来,基本的功能框架是存在的。@Cameron:我意识到我参加聚会已经很晚了,但作为Eric Lippert博客的常客(他曾经从事C#编译器的工作)我认为C#编译器不允许重载setter的最有可能的解释是:它根本没有被视为一种有用或足够重要的语言特性。正如Eric经常指出的那样,实现一个特性是有成本的,所以除非一个特性不是很需要,否则它不会存在。LinqPad展示了IL的简化视图。我认为ildasm的输出在这里会更有帮助。因为它会显示
.property
,并且您在那里设置了getter和setter。@svick D就是这样一种语言。setter有一个只有一个参数的方法。与方法一样,您可以有多个不同类型的方法。