ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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;
}

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

现在这是问题所在:

我不想复制设置代码。在这种情况下,只设置了一个字段,但当然可能不止一个。要使字段只读,我需要从构造函数中设置它们,因此我不能将共享代码“提取”到实用程序函数中。我不知道如何从另一个构造函数中调用一个构造函数。

有任何想法吗?


A
AustinWBryan

像这样:

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

@Avi:您可以创建一个操纵参数的 static 方法。
我可以知道这个的执行顺序吗? Sample(string) 中的所有内容都将首先执行然后 Sample(int) 或者 int 版本将首先执行然后它会返回到字符串版本? (就像在 Java 中调用 super() 一样?)
@RosdiKasim:基类构造函数总是首先运行。在初始化其基类之前,您无法使用或查看 this
@ivan_pozdeev:是的,你可以;使用 ?: 或调用静态方法。
@GeorgeBirbilis:是的。他想在调用另一个 ctor 之前运行代码(在参数上)。在这一点上,没有实例。
A
AustinWBryan

如果没有在自己的方法中进行初始化就无法令人满意地实现您想要的(例如,因为您想在初始化代码之前做太多事情,或者将其包装在 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);
}

+1真正的解决方案。使用 base(...)this(...) 我们只能执行非常有限的操作。
完全同意 - 其他解决方案有效,但不是正确的方法(TM)!
使用 out 关键字代替 ref 怎么样?
@nawfal:因为如果变量是 readonly,它就不能这样做。
@JohnCarpenter:如果只需要设置一个 readonly 字段,设置它的代码可以调用方法并使用返回值分配字段,但是可以直接使用 ref 编写任意数量的字段。此外,如果重要,通过 ref 参数所做的更改会立即发生,甚至在函数返回之前,而使用函数返回值所做的更改则不会。
P
Peter Mortensen

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

: base (parameters)

: this (parameters)

例子:

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

不幸的是,如果我需要对构造函数调用之间的参数进行一些操作,则不起作用。
@Denis你不能在中间链接一个构造函数来达到同样的效果吗?
@Denis 在调用构造函数之前你不能做任何事情。如果您想在初始化对象的属性之前做一些事情,请在构造函数示例 init() 之外的方法中移动初始化。您可以从任何构造函数中调用此方法。
@AbdullahShoaib 当您需要调用父构造函数时不需要。
F
Faisal Mq

我正在改进 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
p
pasx

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

    public SomeClass(int i)
    {
        I = i;
    }

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

如果您在某些情况下使用默认构造函数,并为其他情况进行小的/特定的更改,这可能会更干净。
M
Maurício Júnior

是的,您可以在调用基础或此之前调用其他方法!

public class MyException : Exception
{
    public MyException(int number) : base(ConvertToString(number)) 
    {
    }

    private static string ConvertToString(int number) 
    { 
      return number.toString()
    }

}

只是为了整体答案-如果您的构造函数应该初始化任何只读字段,则不能为此使用方法。
S
SUNIL DHAPPADHULE

构造函数链接,即当您想在单个调用中调用多个构造函数时,您可以使用“Base”作为关系,“This”可以用于同一个类。

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

M
Martin Backasch

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

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


K
Kasper Halvas Jensen

错误处理和使您的代码可重用是关键。我在 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;
        }
}

K
Keep Thinking

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

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 会非常有用。


E
Erdogan Kurtur

请、请、请不要在家里、工作或任何地方尝试这个。

这是一种解决非常具体的问题的方法,我希望你不会有这种情况。

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

我再说一遍,在任何情况下都不要使用它。代码是用 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 });
    }
}

由于构造函数是一种方法,因此您可以通过反射调用它。现在您要么使用门户进行思考,要么想象一罐蠕虫的图片。为此表示歉意。


M
Mark Ainsworth

就我而言,我有一个使用 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 在代码的其他地方定义;我的主要构造函数已针对此插图进行了简化。