2013-06-13 4 views
2

Редактировать: Спасибо всем, ребята. Я в долгу перед тобой.Попытка инициировать PointF с параметром

Я работаю над программой, которая отображает функцию между двумя значениями. Вот код:

public partial class Form2 : Form 
{ 
    public class E 
    { 
     public static double A; 
     public static double B; 
     public static double C; 
     public static int s1; 
     public static int s2; 
     public static int K=(s2 - s1) * 18; 
    } 

    public Form2(double a, double b, double c, double s1, double s2) 
    { 
     InitializeComponent(); 
     E.A = a; 
     E.B = b; 
     E.C = c * 1.3333; 
     E.s1 = Convert.ToInt32(s1); 
     E.s2 = Convert.ToInt32(s2); 

     this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint); 

     Calc(); 
    } 

    public PointF[] p = new PointF[E.K]; //Value in E.K isn't applied here :(

    private void Calc() 
    { 
     for (int x = 18 * E.s1; x < 18 * E.s2; x++) 
     { 
      double res = (E.A * Math.Pow(x, E.B) + E.C); 
      p[x - 18 * E.s1] = new PointF(x, (float)res); 
     } 
    } 

    private void Form1_Paint(object sender, PaintEventArgs e) 
    { 
     float Y = (float)E.C; 
     e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; 
     e.Graphics.TranslateTransform(203, 203 + 14 * (-Y)); 
     if (E.B == 0 || E.B == 1) 
     { 
      e.Graphics.ScaleTransform(1, -1F); 
     } 
     else 
     { 
      e.Graphics.ScaleTransform(1F, -0.05F); 
     } 

     e.Graphics.DrawLines(Pens.Blue, p); 

    } 

я сделал некоторый анализ, и обнаружил, что, когда E.K идет внутри функции PointF, получается 0, поэтому программа дает IndexOutOfRangeException. У вас есть какие-то предложения или альтернативные идеи?

+0

Добро пожаловать на переполнение стека! Пожалуйста, см. [Этот ответ] (http://meta.stackexchange.com/a/130208/213671), чтобы понять, почему я редактировал ваш заголовок. – gunr2171

ответ

1

Это должно быть выполнено с целью создания/инициализации объекта. Проблема заключается в том, что E.s1 и E.s2 не инициализируется поэтому рассмотрят следующее:

public class E 
{ 
    ... 
    public static int s1; 
    public static int s2; 
    public static int K=(s2 - s1) * 18; 
} 

// outside of a constructor 
public PointF[] p = new PointF[E.K]; 

public Form2(double a, double b, double c, double s1, double s2) 
{ 
    // inside the constructor 
    E.s1 = Convert.ToInt32(s1); 
    E.s2 = Convert.ToInt32(s2); 
} 

Статических инициализаторы полей выполняются перед инициализаторами типа и экземпляр инициализаторы выполняются перед конструкторами. Поэтому, когда новый экземпляр Form2 создается происходит следующее:

  1. инициализацию все статические поля Form2, если таковые имеются (но там нет).
  2. вызовов типа инициализатора для Form2, если есть один (но там нет)
  3. инициализации всех экземпляры полого Form2, если таковой имеется.
    • Инициализирует p, но так как он использует E.K, в этот момент он инициализирует класс E.
      1. инициализацию все статические поля E, если таковые имеются:
      2. K = (s2 - s1) * 18, но так как s1 и s2 не инициализируются это имеет значение K = 0.
      3. вызовы типа инициализатора для E, если есть один (но не)
  4. Вызывает конструктор для Form2, если есть один
    • E.s1 = Convert.ToInt32(s1); и E.s2 = Convert.ToInt32(s2);
      Но на данный момент это не влияет на p, потому что он уже инициализирован.

Это может быть запутанным и сложным. По этой причине настоятельно рекомендуется избегать такой структуры. Используйте конструкторы для управления порядком, в котором создаются экземпляры, и введите инициализаторы для управления порядком, в котором создаются члены экземпляра. Кроме того, избегайте использования статических полей в качестве простого захватного мешка для свойств, особенно когда эти свойства меняются в течение жизни программы.Я бы рекомендовал рефакторинга класс на что-то вроде этого:

public class E 
{ 
    public double A; 
    public double B; 
    public double C; 
    public int s1; 
    public int s2; 
    public int K { get { return (s2 - s1) * 18; } } 
} 

private E e; 
private PointF[] p; 

public Form2(double a, double b, double c, double s1, double s2) 
{ 
    ... 
    e = new E(); 
    e.A = a; 
    e.B = b; 
    e.C = c * 1.3333; 
    e.s1 = Convert.ToInt32(s1); 
    e.s2 = Convert.ToInt32(s2); 
    p = new PointF[e.K]; 
    ... 
} 

private void Calc() 
{ 
    for (int x = 18 * e.s1; x < 18 * e.s2; x++) 
    { 
     double res = (e.A * Math.Pow(x, e.B) + e.C); 
     p[x - 18 * e.s1] = new PointF(x, (float)res); 
    } 
} 

private void Form1_Paint(object sender, PaintEventArgs e) 
{ 
    float Y = (float)this.e.C; // this.e avoids confusion with parameter e 
    ... 
} 

Конечно, E класс является несколько излишним сейчас, все его поля могут быть так же легко хранить непосредственно в Form2, но это по крайней мере облегчает передать все эти поля в другой класс, если это необходимо (возможно, именно поэтому вы решили использовать статику в первую очередь).

Я бы также рекомендовал использовать более одного или двух имен символов для классов или полей. Это затрудняет определение того, что должен делать код.

0

Как изменить значение s1 и s2, значение K воли НЕ обновления автоматически. Для того, чтобы заставить его работать, как и следовало ожидать, изменить K к ReadOnly собственности так рассчитывается с текущими значениями s1 и s2:

public class E 
{ 

    public static double A; 
    public static double B; 
    public static double C; 
    public static int s1; 
    public static int s2; 

    public static int K 
    { 
     get 
     { 
      return (s2 - s1) * 18; 
     } 
    } 

} 
+0

Это не единственное неправильное с кодом OP; он не будет исправлять «IndexOutOfRangeException». –

Смежные вопросы