重载属性设置器

时间:2015-04-06 23:27:47

标签: c#

我在看this question,这让我很奇怪。

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

// 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 所示。

这是否与语言设计师如何设计语言的工作和行为有关?

3 个答案:

答案 0 :(得分:1)

你确实可以这样做......

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重载。但是,您可以使用implicit type conversion实现类似的功能,但必须在您自己的类型上实现。整数是一种值类型,因此它本身就是密封的。

答案 1 :(得分:1)

不是JIT生成属性的get_*set_*方法。

如果您反编译此代码:

public int MyInt { get; set; }

你会得到这个IL:

.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

如果您查看PropertyInfo,则会看到它有GetMethodSetMethod。 &#34;方法&#34;,不&#34;方法&#34;。

这与框架有关,虽然我不知道某个属性有多个getter或setter的语言。你知道这种语言吗?

答案 2 :(得分:0)

C#设计师确实让我们能够实现隐式类型转换。但是,他们可能不希望这种情况与原始类型一起使用以避免混淆。

想象一下这句话:

var myvar = 2;
myvar = "4";

任何关注上述内容的人都会认为我们正在谈论像JavaScript这样的动态语言。在JavaScript中,myvar将是第二行的字符串。如果C#支持您描述的内容,那么它仍然是int。例如,我会发现它令人困惑。