我有两个构造函数,它们将值提供给只读字段。
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;
}
一个构造函数直接接收值,另一个进行一些计算并获取值,然后设置字段。
现在这是问题所在:
我不想复制设置代码。在这种情况下,只设置了一个字段,但当然可能不止一个。要使字段只读,我需要从构造函数中设置它们,因此我不能将共享代码“提取”到实用程序函数中。我不知道如何从另一个构造函数中调用一个构造函数。
有任何想法吗?
像这样:
public Sample(string str) : this(int.Parse(str)) { }
如果没有在自己的方法中进行初始化就无法令人满意地实现您想要的(例如,因为您想在初始化代码之前做太多事情,或者将其包装在 try-finally 中,或其他任何东西),您可以拥有任何或全部构造函数通过引用初始化例程将只读变量传递给初始化例程,然后该例程将能够随意操作它们。
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);
}
base(...)
或 this(...)
我们只能执行非常有限的操作。
out
关键字代替 ref
怎么样?
readonly
,它就不能这样做。
readonly
字段,设置它的代码可以调用方法并使用返回值分配字段,但是可以直接使用 ref
编写任意数量的字段。此外,如果重要,通过 ref
参数所做的更改会立即发生,甚至在函数返回之前,而使用函数返回值所做的更改则不会。
在构造函数的主体之前,使用:
: base (parameters)
: this (parameters)
例子:
public class People: User
{
public People (int EmpID) : base (EmpID)
{
// Add more statements here.
}
}
init()
之外的方法中移动初始化。您可以从任何构造函数中调用此方法。
我正在改进 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);
}
}
new Sample(str, false)
创建示例而不进行设置。
this
调用另一个构造函数,则让该构造函数调用 setupStuff
;在最后一个构造函数中删除对 setupStuff 的调用。那么您就不需要 doStuff
/ false
参数了。 (一个较小的抱怨是,如果您确实有理由使用 doStuff
参数,那么将其设为可为空的布尔 bool?
没有任何好处。只需使用 bool
。)此外,Teejay 指出,这意味着这是一个致命缺陷的设计。
public Sample(string theIntAsString) : this(int.Parse(theIntAsString)) {}
public Sample(int theInt) { setupStuff(ref _intField, theInt); }
请注意,第一个构造函数调用另一个构造函数,不调用 setupStuff
。
这是一个调用另一个构造函数的示例,然后检查它设置的属性。
public SomeClass(int i)
{
I = i;
}
public SomeClass(SomeOtherClass soc)
: this(soc.J)
{
if (I==0)
{
I = DoSomethingHere();
}
}
是的,您可以在调用基础或此之前调用其他方法!
public class MyException : Exception
{
public MyException(int number) : base(ConvertToString(number))
{
}
private static string ConvertToString(int number)
{
return number.toString()
}
}
构造函数链接,即当您想在单个调用中调用多个构造函数时,您可以使用“Base”作为关系,“This”可以用于同一个类。
class BaseClass
{
public BaseClass():this(10)
{
}
public BaseClass(int val)
{
}
}
class Program
{
static void Main(string[] args)
{
new BaseClass();
ReadLine();
}
}
从基类继承类时,可以通过实例化派生类来调用基类构造函数
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);
}
}
sample program 的输出是
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);
}
}
此 sample program 的输出是
20
错误处理和使您的代码可重用是关键。我在 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 在代码的其他地方定义;我的主要构造函数已针对此插图进行了简化。
不定期副业成功案例分享
static
方法。Sample(string)
中的所有内容都将首先执行然后Sample(int)
或者 int 版本将首先执行然后它会返回到字符串版本? (就像在 Java 中调用super()
一样?)this
。?:
或调用静态方法。