C# 使属性只能由特定方法设置

C# 使属性只能由特定方法设置,c#,properties,enums,C#,Properties,Enums,我在试着做一个化学等式平衡的东西。为此,我创建了一个类元素: class Element { public elemEnum ElemType {get; set;} public double Amount {get; set;} // How many atoms of this type in the formula } *elemEnum是所有化学元素的枚举 我想为ElemType设置set解析枚举字符串,但由于set只能接受与value相同类型的值,我决定添加一个方法

我在试着做一个化学等式平衡的东西。为此,我创建了一个类元素:

class Element
{
    public elemEnum ElemType {get; set;}
    public double Amount {get; set;} // How many atoms of this type in the formula
}
*
elemEnum
是所有化学元素的枚举

我想为
ElemType
设置
set
解析枚举字符串,但由于
set
只能接受与
value
相同类型的值,我决定添加一个方法:

public void SetElemType(string type)
{
    this.ElemType = (elemEnum)Enum.Parse(typeof(elemEnum), type);
}

有没有一个选项可以让
ElemType
属性只能由
SetElemType
方法设置,而不必将其设置为
private
并添加
GetElemType
方法?

如前所述,您可以使用
private setter
,或者,您可以将
readonly
属性与使用字段和方法的
public getter
一起使用来修改此字段:

class Element
{
   private elemEnum _elemType;

   public elemEnum ElemType { get { return _elemType; } }

   public void SetElemType(string type) 
   {
      this._elemType = (elemEnum)Enum.Parse(typeof(elemEnum), type);
   }

   public double Amount {get; } // How many atoms of this type in the formula
}
虽然它实际上与私有setter的属性相同,但它使用的方法略有不同

如果您确实希望只允许一个(!)方法更改值,则可以使用反射并添加封装枚举的类:

class MyElemSetter
{
    private readonly elemEnum elem;

    public MyElemSetter(elemEnum e, Action helperAction)
    {
        MethodInfo callingMethodInfo = helperAction.Method;

        if (helperAction.Method.Name.Contains("<SetElemType>")) elem = e;
    }

    public static implicit operator elemEnum(MyElemSetter e)
    {
        return e.elem;
    }
}

class Element
{
    private MyElemSetter _elemType;

    public elemEnum ElemType { get { return _elemType; } }

    public void SetElemType(string type)
    {
        this._elemType = new MyElemSetter((elemEnum)Enum.Parse(typeof(elemEnum), type), () => { });
    }

    public double Amount { get; set; } // How many atoms of this type in the formula
}
类MyElemSetter
{
私有只读elemEnum elem;
公共MyElemSetter(elemEnum e,Action helperAction)
{
MethodInfo callingMethodInfo=helperAction.Method;
if(helperAction.Method.Name.Contains(“”)elem=e;
}
公共静态隐式运算符elemEnum(MyLemsetter e)
{
返回e.elem;
}
}
类元素
{
私有MyElemSetter_elemType;
公共elemEnum ElemType{get{return{u ElemType;}}
公共void SetElemType(字符串类型)
{
这个._elemType=newmyelemsetter((elemEnum)Enum.Parse(typeof(elemEnum),type),()=>{});
}
public double Amount{get;set;}//公式中有多少个这种类型的原子
}
不必把它保密

您可以通过向类中添加
bool
字段并稍微修改属性来创建一个变通解决方案

class Element
{
    private bool _elemCanBeSet = false;
    private elemNum _elemType;

    public elemEnum ElemType
    {
        get { return _elemType; }
        set { if (_elemCanBeSet) _elemType = value; }
    }

    public double Amount {get; set;} // How many atoms of this type in the formula

    public void SetElemType(string type)
    {
        _elemCanBeSet = true;
        this.ElemType = (elemEnum)Enum.Parse(typeof(elemEnum), type);
        _elemCanBeSet = false;
    }
}

此解决方案可能会使使用您的类的开发人员感到困惑,因为设置属性将无效。正如其他人所说,在你的任务中使用一个私人的setter是更好的。我只是想展示另一种方法。

因为评论中最明显的解决方案并不是作为答案编写的:

使用一个。
这样,
ElemType
只能从您自己的类中设置。

C#中有私有的getter/setter
public elemEnum ElemType{get;private set;}
。您尝试过使用它吗?对于您的问题,我认为不可能使用auto setter/getter方法来接受与变量类型不同的类型。您可以将ElemType的setter设置为private,以确保它只能在类中的表单中设置。可能是主题,但C#中的类型名称应该是pascal大小写,意思是“elemEnum”应该是“elemEnum”好的,也许你可以这样做,这样属性的用途是什么?常见的解决方案是使用私有setter,如Caramiriel的评论所示。您的属性可能仍然由类的其他成员设置,但这不应该成为问题,因为您可以完全控制类的实现。@edost我不知道有私有的set/getter。我对大写的不好,我对这个有点陌生,我将来会注意到。为什么你会喜欢这个而不是现有的语言结构-私有setters?@Rotem这个OP几乎被要求避免现有的语言结构。我认为你的评论应该是对这个问题的评论,而不是对这个答案的评论。我只是想展示一下,如何在不将属性私有化的情况下实现OP想要的东西(参见我文章开头的引文)。@hvd OP问他们如何避免将整个属性私有化(因此必须提供额外的手动getter和setter)。OP不知道私有setter。Lol如果我们添加另一个方法,将
\u elemCanBeSet
更改为
true
,然后毫无问题地修改值,会怎么样?在这种情况下,这会有什么帮助?我不确定将其设置为私有setter是否是最好的解决方案,如果目标是使一个只能通过该方法设置的pro-party,那么仅将其设置为私有将不起作用。因为该类中的任何方法都可以编辑该值。因此,我认为卡波尔的答案是解决这个问题的更好办法。@EdoPost我怀疑OP是在试图保护它不受自己类的方法的影响,而不是受到外部操纵。@EdoPost是的,Rotem是正确的。除了属性、构造函数和方法之外,这个类可能根本就不会保存任何东西。
class Element
{
    public ElemEnum ElemType {get; private set;}
    public double Amount {get; set;}

    public void SetElemType(string type)
    {
        this.ElemType = (ElemEnum)Enum.Parse(typeof(ElemEnum), type);
    }
}