如果我使用初始化列表,我的属性是否会被赋予默认值?

时间:2010-11-30 20:10:32

标签: c# initialization

我有一个类,

public class Revex
{
    public IEnumerable<char> AllCharacters = Enumerable.Range(0, 256).Select(Convert.ToChar).Where(c => !char.IsControl(c)).ToArray();
    // ...

如果我用

初始化它
var r = new Revex { AllCharacters = "abcd" };

以上行是否会被执行(Enumerable.Range ...)?当我以这种方式构建课程时,如果我希望它 not 被调用,我该怎么做?

我有大约10个这样的可选字符类,所以我不想为它们的每个可能组合编写构造函数。

3 个答案:

答案 0 :(得分:2)

这样的初始化成员变量总是在构造函数中执行代码之前初始化。

在这种情况下,您有以下顺序

  1. 初始化AllCharacters成员变量
  2. 运行Revex构造函数(可能是编译器提供的默认“不执行任何操作”构造函数)
  3. AllCharacters
  4. 分配新值

    如果要避免此序列,则需要将AllCharacters的初始化移动到构造函数中。

    如果您还想允许可能的覆盖,则可能需要以下内容:

    public class Revex
    {
        public IEnumerable<char> AllCharacters;
    
        public Revex()
            : this( Enumerable.Range(0, 256)
                    .Select(Convert.ToChar)
                    .Where(c => !char.IsControl(c))
        {
            // Nothing
        }
    
        public Revex(IEnumerable<char> allCharacters)
        {
            AllCharacters = allCharacters.ToArray();
        }
    }
    

    12月3日更新

    另一种替代方法是仅在类消费者未提供显式值时才使用延迟初始化来提供默认值。您需要切换到公共属性而不是公共字段,并在属性getter中提供逻辑。

    public class Revex
    {
        public IEnumerable<char> AllCharacters
        {
            get
            {
                if (mAllCharacters == null)
                {
                    // Default initialization
                    mAllCharacters 
                        = Enumerable.Range(0, 256)
                          .Select(Convert.ToChar)
                          .Where(c => !char.IsControl(c)
                }
    
                return mAllCharacters;
            }
        }
    
        public Revex()
        {
            // Nothing
        }
    
        private IEnumerable<char> mAllCharacters;
    }
    

答案 1 :(得分:2)

var r = new Revex { AllCharacters = "abcd" };

的语法糖
var r = new Revex();
r.AllCharacters = "abcd";

很明显,AllCharacters字段将被初始化为默认值。

如果您不想使用默认值,则可以执行此操作

public class Revex{

  public IEnumerable<char> AllCharacters;

  public Revex(){
     AllCharacters = Enumerable.Range(0, 256).Select(Convert.ToChar).Where(c => !char.IsControl(c)).ToArray()
  }

  public Revex(IEnumerable<char> allCharacters){
    AllCharacters = allCharacters;
  }

}

还有一个选项:

public class Regex{

    private static IEnumerable<char> DefaultAllCharacters(){ return Enumerable.Range.. }

    private IEnumerable<char> allCharacters;

    public IEnumerable<char> AllCharacters{
        get { return allCharacters ?? (allCharacters = DefaultAllCharacters()); }
        set { allCharacters = value; }
    }

}

如果尚未设置属性值,则懒惰地初始化该属性值。因此,如果尚未设置值,则不支付设置值的前期成本,但是一旦创建了对象,您就需要支付它。

答案 2 :(得分:1)

如果使用声明初始化类变量,则会进行初始化。因此,在这种情况下,您的字段将被设置两次,一次创建类,然后再设置属性。

如果您希望初始化是可选的,那么您需要将其声明为:

public IEnunerable<char> AllCharacters;

然后,您需要在构造函数中初始化它,或者通过设置属性来完成它。