Ошибка переполнения стека C # с получателем и установщиком - PullRequest
1 голос
/ 17 августа 2011

Это рабочий класс:

namespace Lite
{
    public class Spec
    {
        public int ID { get; set; }

        public string Name { get; set; }
        public string FriendlyName { get; set; }
        public int CategoryID { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public string UOM { get; set; }
        public int Pagination { get; set; }
        public int ColoursFront { get; set; }
        public int ColoursBack { get; set; }
        public string Material { get; set; }
        public int GSM { get; set; }
        public string GSMUOM { get; set; }
        public bool Seal { get; set; }

        public Spec(int ID)
        {
            using (CrystalCommon.MainContext db = new CrystalCommon.MainContext())
            {
                var q = (from c in db.tblSpecifications where c.id == ID select c).SingleOrDefault();
                if (q != null)
                    loadByRec(q);
            }
        }

        public Spec(CrystalCommon.tblSpecification Rec)
        {
            loadByRec(Rec);
        }

        public void loadByRec(CrystalCommon.tblSpecification Rec)
        {
            this.ID = Rec.id;
            this.Name = Rec.Title;
            this.Width = Convert.ToInt32(Rec.FinishedSizeW.Value);
            this.Height = Convert.ToInt32(Rec.FinishedSizeL.Value);
            this.UOM = Rec.FlatSizeUOM;
            this.Pagination = Rec.TxtPagination.Value;
            this.ColoursFront = Convert.ToInt32(Rec.TxtColsF.Value);
            this.ColoursBack = Convert.ToInt32(Rec.TxtColsB.Value);
            this.Material = Rec.TxtMaterial;
            this.GSM = Rec.TxtGSM.Value;
            this.GSMUOM = Rec.txtGsmUnit;
            this.Seal = Rec.TxtSeal.Value == 1;
        }

        public string displayDimensions()
        {
            return Width + " x " + Height + " " + UOM;
        }
    }
}

Затем я пытаюсь изменить Name getter и setter:

namespace Lite
{
    public class Spec
    {
        public int ID { get; set; }

        // User friendly name if available otherwise fall back on spec name
        public string Name { get {
            if (null != FriendlyName)
                return FriendlyName;
            else
                return Name;
            }
            set
            {
                Name = value;
            }
        }
        public string FriendlyName { get; set; }
        public int CategoryID { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public string UOM { get; set; }
        public int Pagination { get; set; }
        public int ColoursFront { get; set; }
        public int ColoursBack { get; set; }
        public string Material { get; set; }
        public int GSM { get; set; }
        public string GSMUOM { get; set; }
        public bool Seal { get; set; }

        public Spec(int ID)
        {
            using (CrystalCommon.MainContext db = new CrystalCommon.MainContext())
            {
                var q = (from c in db.tblSpecifications where c.id == ID select c).SingleOrDefault();
                if (q != null)
                    loadByRec(q);
            }
        }

        public Spec(CrystalCommon.tblSpecification Rec)
        {
            loadByRec(Rec);
        }

        public void loadByRec(CrystalCommon.tblSpecification Rec)
        {
            this.ID = Rec.id;
            this.Name = Rec.Title;
            this.Width = Convert.ToInt32(Rec.FinishedSizeW.Value);
            this.Height = Convert.ToInt32(Rec.FinishedSizeL.Value);
            this.UOM = Rec.FlatSizeUOM;
            this.Pagination = Rec.TxtPagination.Value;
            this.ColoursFront = Convert.ToInt32(Rec.TxtColsF.Value);
            this.ColoursBack = Convert.ToInt32(Rec.TxtColsB.Value);
            this.Material = Rec.TxtMaterial;
            this.GSM = Rec.TxtGSM.Value;
            this.GSMUOM = Rec.txtGsmUnit;
            this.Seal = Rec.TxtSeal.Value == 1;
        }

        public string displayDimensions()
        {
            return Width + " x " + Height + " " + UOM;
        }
    }
}

На моем компьютере это компилируется нормально, но серверкажется, сбой при запуске.(Первая версия работает отлично).Мой коллега скомпилировал его на своем компьютере, и он, по-видимому, выдал «ошибку переполнения стека», но сейчас он не для меня, чтобы узнать подробности об этом.

Правильно ли я применяю метод получения здесь?

Ответы [ 8 ]

11 голосов
/ 17 августа 2011

Это бесконечный цикл:

public string Name { get {
  ...
  set
  {
    Name = value;
  }
}

Сеттер будет вызывать себя несколько раз, пока вы не получите исключение переполнения стека.

обычно у вас есть резервная переменная, поэтому она выглядит так

private string name;
public string Name { 
  get {
    if (null != FriendlyName)
      return FriendlyName;
    else
      return name;
    }
  set {
    name = value;
  }
}
5 голосов
/ 17 августа 2011

Ваш набор ссылается на само свойство, а ваш get ссылается на само свойство, оба они вызовут потенциально бесконечный цикл, ведущий к StackOverflowException (больше нет места в стеке для вставки текущего вызова). Вам необходимо использовать вспомогательное поле:

private string _name;

public string Name 
{ 
    get 
    {
        if (null != FriendlyName)
            return FriendlyName;
        else
            return _name;
    }
    set
    {
        _name = value;
    }
}

Похоже, вы пытались превратить автоматическое свойство в ручное. Авто-свойства (public string Name { get; set; }) работают, потому что компилятор создаст само поле поддержки.

В качестве учебного упражнения, если вы пройдете через отладчик и перейдете в return Name или Name = value, вы увидите из первых рук, что код возвращается в свойство, в котором вы уже находитесь.

2 голосов
/ 17 августа 2011

Это намного лучше.

string _name = "";
public string Name
{
    get { return FriendlyName ?? _name; }
    set { _name = value; }
}
1 голос
/ 17 августа 2011

У вас есть геттер для Name, который вызывает свойство Name, который будет вызывать геттер для Name и т. Д. Вам необходимо личное поле для поддержки свойства, и вместо этого вам нужно получить доступ к этому полю поддержки в вашем геттере.

1 голос
/ 17 августа 2011

Одно из ваших свойств получает и устанавливает себя, см .:

   public string Name
   {
       get {
        if (null != FriendlyName)
            return FriendlyName;
        else
            return Name; //<-- StackOverflow
        }
        set
        {
            Name = value; //<-- StackOverflow
        }
    }
0 голосов
/ 17 августа 2011

Нет, вы должны использовать вспомогательное поле. Ошибка в else

        public string Name { get {
        if (null != FriendlyName)
            return FriendlyName;
        else
            return Name;//error, you're calling the property getter again.
        }
0 голосов
/ 17 августа 2011

Если FriendlyName равно null, то получатель Name пытается получить значение от получателя Name, т.е. он зацикливается.Это то, что вызывает переполнение стека.

0 голосов
/ 17 августа 2011
public string Name { get {
            if (null != FriendlyName)
                return FriendlyName;
            else
                return Name;
            }
            set
            {
                Name = value;
            }
        }

Name в get / set относится к недвижимости. Вам нужно будет определить вспомогательное поле и использовать его.

...