从一个构造函数调用另一个构造函数

我有两个构造函数,它们将值提供给只读字段。

public class Sample{public Sample(string theIntAsString){int i = int.Parse(theIntAsString);_intField = i;}
public Sample(int theInt) => _intField = theInt;public int IntProperty    => _intField;
private readonly int _intField;}

一个构造函数直接接收值,另一个进行一些计算并获取值,然后设置字段。

现在这里是捕获:

  1. 我不想复制设置代码。在这种情况下,只有一个场设置,但当然有可能我们不止一个。
  2. 要使字段只读,我需要从构造函数中设置它们,所以我无法“提取”共享代码一个实用函数。
  3. 我不知道怎么叫另一个构造函数。

有什么想法吗?

607897 次浏览

像这样:

public Sample(string str) : this(int.Parse(str)) { }

在构造函数的主体之前,使用:

: base (parameters)
: this (parameters)

示例:

public class People: User{public People (int EmpID) : base (EmpID){// Add more statements here.}}

如果你想要的东西不能在没有初始化自己的方法的情况下令人满意地实现(例如,因为你想在初始化代码之前做太多的事情,或者把它包装在一个try-最终,或者其他什么),你可以让任何或所有的构造函数通过引用一个初始化例程来传递只读变量,然后它将能够随意操作它们。

public class Sample{private readonly int _intField;public int IntProperty => _intField;
private void setupStuff(ref int intField, int newValue) => intField = newValue;
public Sample(string theIntAsString){int i = int.Parse(theIntAsString);setupStuff(ref _intField,i);}
public Sample(int theInt) => setupStuff(ref _intField, theInt);}

我正在改进Supercat的答案。我想也可以做到以下几点:

class Sample{private readonly int _intField;public int IntProperty{get { return _intField; }}
void setupStuff(ref int intField, int newValue){//Do some stuff here based upon the necessary initialized variables.intField = newValue;}
public Sample(string theIntAsString, bool? doStuff = true){//Initialization of some necessary variables.//==========================================int i = int.Parse(theIntAsString);// ................// .......................//==========================================
if (!doStuff.HasValue || doStuff.Value == true)setupStuff(ref _intField,i);}
public Sample(int theInt): this(theInt, false) //"false" param to avoid setupStuff() being called two times{setupStuff(ref _intField, theInt);}}

这是一个调用另一个构造函数的示例,然后检查它设置的属性。

    public SomeClass(int i){I = i;}
public SomeClass(SomeOtherClass soc): this(soc.J){if (I==0){I = DoSomethingHere();}}

从基类继承类时,可以通过实例化派生类来调用基类构造函数

class sample{public int x;
public sample(int value){x = value;}}
class der : sample{public int a;public int b;
public der(int value1,int value2) : base(50){a = value1;b = value2;}}
class run{public static void Main(string[] args){der obj = new der(10,20);
System.Console.WriteLine(obj.x);System.Console.WriteLine(obj.a);System.Console.WriteLine(obj.b);}}

样本程序的输出是

50 10 20


您还可以使用this关键字从另一个构造函数调用构造函数

class sample{public int x;
public sample(int value){x = value;}
public sample(sample obj) : this(obj.x){}}
class run{public static void Main(string[] args){sample s = new sample(20);sample ss = new sample(s);
System.Console.WriteLine(ss.x);}}

这个样本程序的输出是

20

是啊,你可以调用其他方法之前的调用基地或这个!

public class MyException : Exception{public MyException(int number) : base(ConvertToString(number)){}
private static string ConvertToString(int number){return number.toString()}
}

构造函数链即,当您想在单个调用中调用多个构造函数时,您可以将“Base”用于Is关系,并将“this”用于同一个类。

  class BaseClass{public BaseClass():this(10){}public BaseClass(int val){}}class Program{static void Main(string[] args){new BaseClass();ReadLine();}}

错误处理和使您的代码可重用是关键。我在int验证中添加了字符串,如果需要,可以添加其他类型。使用更可重用的解决方案解决这个问题可能是这样的:

public class Sample{public Sample(object inputToInt){_intField = objectToInt(inputToInt);}
public int IntProperty => _intField;
private readonly int _intField;}
public static int objectToInt(object inputToInt){switch (inputToInt){case int inputInt:return inputInt;break;case string inputString:if (!int.TryParse(inputString, out int parsedInt)){throw new InvalidParameterException($"The input {inputString} could not be parsed to int");}return parsedInt;
default:throw new InvalidParameterException($"Constructor do not support {inputToInt.GetType().Name}");break;}}

如果您需要在调用另一个构造函数之前而不是之后运行某些东西。

public class Sample{static int preprocess(string theIntAsString){return preprocess(int.Parse(theIntAsString));}
static int preprocess(int theIntNeedRounding){return theIntNeedRounding/100;}
public Sample(string theIntAsString){_intField = preprocess(theIntAsString)}
public Sample(int theIntNeedRounding){_intField = preprocess(theIntNeedRounding)}
public int IntProperty  => _intField;
private readonly int _intField;}

如果您需要设置多个字段,ValueTuple会非常有用。

拜托,拜托,漂亮的请不要在家里尝试这个,或者工作,或者任何地方。

这是一个解决非常非常具体问题的方法,我希望你不要这样做。

我发布这个,因为它在技术上是一个答案,另一个角度来看待它。

我重复一遍,在任何情况下都不要使用它。代码将使用LINQPad运行。

void Main(){(new A(1)).Dump();(new B(2, -1)).Dump();    
var b2 = new B(2, -1);b2.Increment();    
b2.Dump();}
class A{public readonly int I = 0;    
public A(int i){I = i;}}
class B: A{public int J;public B(int i, int j): base(i){J = j;}    
public B(int i, bool wtf): base(i){}    
public void Increment(){int i = I + 1;
var t = typeof(B).BaseType;var ctor = t.GetConstructors().First();        
ctor.Invoke(this, new object[] { i });}}

由于构造函数是一个方法,你可以用反射调用它。现在你要么用门户思考,要么想象一张一罐虫子的图片。对不起。

在我的例子中,我有一个使用OracleDataReader作为参数的主构造函数,但我想使用不同的查询来创建实例:

我有这个代码:

public Subscriber(OracleDataReader contractReader){this.contract = Convert.ToString(contractReader["contract"]);this.customerGroup = Convert.ToString(contractReader["customerGroup"]);this.subGroup = Convert.ToString(contractReader["customerSubGroup"]);this.pricingPlan= Convert.ToString(contractReader["pricingPlan"]);this.items = new Dictionary<string, Member>();this.status = 0;        
        
}

所以我创建了以下构造函数:

public Subscriber(string contract, string customerGroup) : this(getSubReader(contract, customerGroup)){ }

而这种方法:

 private static  OracleDataReader getSubReader(string contract, string customerGroup){cmdSubscriber.Parameters[":contract"].Value = contract + "%";cmdSubscriber.Parameters[":customerGroup"].Value = customerGroup+ "%";return  cmdSubscriber.ExecuteReader();        
}

注意:静态定义的cmdSubscriber在代码的其他地方定义;为了这个例子,我的主构造函数已经被简化了。

注意:上面的大多数解决方案不适用于结构。

不幸的是,在构造函数调用的方法中初始化结构字段不会被编译器识别,并将导致2个错误:

  • 在构造函数中:字段xxxx必须完全分配…
  • 在方法中,如果您有只读字段:只能在构造函数中分配只读字段。

例如,当您只需要做简单的检查来决定将调用定向到哪个构造函数时,这些可能会非常令人沮丧。