конструктор С#, вызывающий toString

У меня есть объект, который переопределяет iComparable, а также переопределяет toString().

Когда вызывается конструктор, он также вызывает toString(), но не достигает точек останова в методе toString().

Метод toString() также вызывается при выполнении каждой строки конструктора, и как только свойство DataSource обновляется, он получает данные из базы данных и выдает неожиданные результаты.

Я доказал это с помощью ведения журнала environment.stacktrace для каждого вызова.

Является ли это ожидаемым поведением, и есть ли возможность вызывать toString() только тогда, когда я вызываю его явно, а не автоматически.

Код для класса ниже

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Business.Data;

namespace PfWToEpayfactGIF
{
class PsPayChangeDetails : IComparable<PsPayChangeDetails>
{
  public DateTime EffectiveDate { get; set; }
  public String Code { get; set; }
  public string ChangeType { get; set; }

  public int DataSourceX { get; set; }

  private string gradeID;
  private string gradeSubCode;
  private string gradePercentage;
  private string IDField;
  private string salary;
  private string maxOTRateType;
  private string lWeightType;
  private string onTempPromotion;
  private string RTIHoursInd;
  private string paygroupID;
  private string classification;
  private string hoursPayable;
  private string workingPatternID;
  private string OSPSchemeNo;
  private string milestoneDate;
  private string employeeNo;


  public PsPayChangeDetails(string code, DateTime effectiveDate, string changeType, int groupSource)
  {
     EffectiveDate = effectiveDate;
     Code = code;
     ChangeType = changeType;
    DataSourceX = groupSource;
  }

  public void ReadLine(string[] line)
  {
     employeeNo = line[0] != string.Empty ? line[0] : employeeNo;
     try
     {
        if (Code == "E420")
        {
           gradeID = line[4] != string.Empty ? line[4] : gradeID;
           gradeSubCode = line[5] != string.Empty ? line[5] : gradeSubCode;
           gradePercentage = line[6] != string.Empty ? line[6] : gradePercentage;
           IDField = line[7] != string.Empty ? line[7] : IDField;
           salary = line[8] != string.Empty ? line[8] : salary;
           maxOTRateType = line[9] != string.Empty ? line[9] : maxOTRateType;
           lWeightType = line[10] != string.Empty ? line[10] : lWeightType;
           onTempPromotion = line[11] != string.Empty ? line[11] : onTempPromotion;
           RTIHoursInd = line[12] != string.Empty ? line[12] : RTIHoursInd;
        }
        else
        {

           paygroupID = line[4] != string.Empty ? line[4] : paygroupID;
           classification = line[5] != string.Empty ? line[5] : classification;
           hoursPayable = line[6] != string.Empty ? line[6] : hoursPayable;
           workingPatternID = line[7] != string.Empty ? line[7] : workingPatternID;
           OSPSchemeNo = line[8] != string.Empty ? line[8] : OSPSchemeNo;
           milestoneDate = line[9] != string.Empty ? line[9] : milestoneDate;
        }
     }
     catch (IndexOutOfRangeException)
     {
        //ignore the exception as its telling us we dont have all the fields which is fine.
     }

  }

  public override string ToString()
  {
     using (System.IO.StreamWriter write = new System.IO.StreamWriter(@"c:\temp\test.txt", true))
     {
        write.WriteLine(Environment.StackTrace);
     }
        string output = $"{employeeNo},{Code},{EffectiveDate.ToString("dd/MMM/yyyy")},{ChangeType},";
     if (Code == "E420")
     {
        output += $"{gradeID},{gradeSubCode},{gradePercentage},{IDField},{salary},{maxOTRateType},{lWeightType},{onTempPromotion},{RTIHoursInd}";
     }
     else
     {
        using (DataEntities db = new DataEntities(DataSourceX))
        {

           if (paygroupID == null)
           {
              string partTime = workingPatternID == "PT" ? "Y" : "N";
              paygroupID = db.PayGroupEESetting.Where(pge => pge.PartTimeInd == partTime && pge.EnteredDate == db.PayGroupEESetting.Where(pg => pg.PayGroup == pge.PayGroup && pg.EnteredDate <= EffectiveDate).Max(pg => pg.EnteredDate)).OrderBy(pge => pge.PayGroup).FirstOrDefault().PayGroup;
           }
           workingPatternID = workingPatternID == null ? "FT" : "PT";
           if (OSPSchemeNo == null)
           {
              OSPSchemeNo = db.OSPScheme.Min(o => o.SchemeNo).ToString();
           }
        }
        output += $"{paygroupID},{classification},{hoursPayable},{workingPatternID},{OSPSchemeNo},{milestoneDate}";
     }
     return output;
  }


  public int CompareTo(PsPayChangeDetails other)
  {
     if (this.Code == other.Code)
     {
        return this.EffectiveDate.CompareTo(other.EffectiveDate);
     }
     else
     {
        return this.Code.CompareTo(other.Code);
     }
  }
}
}

Спасибо за любую помощь.

Бен


person Ben Whyall    schedule 15.12.2016    source источник
comment
Предоставьте минимальный, полный и поддающийся проверке пример.   -  person Alfie Goodacre    schedule 15.12.2016
comment
Черт возьми, Альфи, я только что напечатал это... ;)   -  person    schedule 15.12.2016
comment
Я не вижу, где вы звоните ToString. Он не вызывается автоматически только потому, что он есть, его нужно где-то вызывать.   -  person HimBromBeere    schedule 15.12.2016
comment
Привет, он автоматически вызывается, и это проблема   -  person Ben Whyall    schedule 15.12.2016
comment
Вскоре я добавлю лучший пример, я постараюсь уменьшить его.   -  person Ben Whyall    schedule 15.12.2016
comment
Почему вы записываете в файл И читаете из базы данных в ToString? ToString может вызываться много, много раз, чего вы не ожидаете. Я настоятельно рекомендую использовать разные методы для ОБОИХ этих действий и не переопределять базовые object методы, которые могут быть вызваны вне вашего контроля.   -  person D Stanley    schedule 15.12.2016
comment
Боже мой, расскажите о неожиданных побочных эффектах от вызова метода.   -  person Dan Wilson    schedule 15.12.2016
comment
@DStanley запись в файл предназначена исключительно для целей отладки. Чтение базы данных связано с тем, что значения по умолчанию различаются в зависимости от клиентской базы данных. Если я изменю его с tostring, он будет работать, как и ожидалось, только тогда, когда это сделано явно.   -  person Ben Whyall    schedule 15.12.2016
comment
И затем вам следует избегать вызова виртуальных (таким образом, потенциально переопределяемых) методов в ваших конструкторах. Это само по себе может иметь побочные эффекты, когда не гарантируется, что ваш класс будет наиболее производным типом (что означает, что вы должны пометить его как запечатанный). Дополнительную информацию об этом можно найти здесь: ссылка   -  person K. Berger    schedule 15.12.2016
comment
@BenWhyall Хорошо, так что плохого в том, чтобы использовать другой метод и вызывать его явно? ToString просто должен представлять ваш текущий объект в виде строки. Поскольку это перегрузка object.ToString, любой код, который получает ссылку на ваш объект и вызывает ToString, будет выполнять этот код. Этот код может находиться в другом потоке, присоединенных процессах (например, отладчике) и т. д., что очень затруднит отладку. Так что, если у вас вопрос, почему это называется, когда я его не называю, вы никогда не узнаете.   -  person D Stanley    schedule 15.12.2016


Ответы (1)


toString() также вызывается при выполнении каждой строки конструктора.

Я предполагаю, что вы знаете это, потому что вы просматриваете код в отладчике. Если это так, то отладчик вызывает ToString для вашего объекта, чтобы представить его в некоторой сетке или другом выводе (локальные переменные, часы и т. д.). Поскольку отладчик находится в другом процессе, он может не сработать какие-либо имеющиеся у вас точки останова.

Суть такова: не используйте ToString ни для чего другого, кроме представления текущего состояния вашего объекта в виде строковой переменной. Если вам нужно загрузить связанные объекты, отформатировать ваш объект определенным образом и т. д., сделайте это за пределами ToString.

person D Stanley    schedule 15.12.2016