2

编辑:谢谢大家,伙计们。我很感激你。

我正在开发一个在两个值之间绘制函数的程序。这是代码:

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. 你们有什么建议或替代想法吗?

4

2 回答 2

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但由于s1s2未初始化,因此计算结果为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,但这至少可以更容易地将所有这些字段传递给另一个类(如果需要)(这可能是你选择使用静态的原因首先)。

我还建议为类或字段使用一个或两个以上的字符名称。很难判断代码的用途。

于 2013-06-13T01:08:00.543 回答
0

当您更改 和 的值时s1s2的值K不会自动更新。为了使它像您期望的那样工作,更改K为只读属性s1,以便使用and的当前值计算它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;
        }
    }

}  
于 2013-06-13T01:11:49.310 回答