创建类和构造函数的难度C#

时间:2012-10-05 03:35:19

标签: c# class constructor visual-studio-2012

我正在尝试为我在学校做的项目实施离散傅立叶变换算法。但创建一个类似乎很难(不应该这样)。 我正在使用Visual Studio 2012。

基本上我需要一个名为Complex的类来存储我从DFT获得的两个值;真实部分和虚部。

这就是我到目前为止所做的:

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

namespace SoundEditor_V3
{
    public class Complex
    {
        public double real;
        public double im;

        public Complex()
        {
            real = 0;
            im = 0;
        }
    }
}

问题在于它不能将构造函数识别为构造函数,我只是在学习C#,但我在网上查找它,这就是它应该看起来的样子。 但它将我的构造函数识别为一种方法。

为什么? 我创造的课程错了吗?

我的傅立叶课也在做同样的事情。所以每次我尝试创建一个 傅里叶对象,然后使用它的方法......没有这样的东西。

例如,我这样做:

Fourier fou = new Fourier();
fou.DFT(s, N,  amp, 0);

它告诉我 fou是'字段'但是像'类型'一样使用 为什么这么说?

以下是我的傅里叶类的代码:

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

namespace SoundEditor_V3
{
   public class Fourier
   {

        //FOURIER
        //N = number of samples
        //s is the array of samples(data)
        //amp is the array where the complex result will be written to
        //start is the where in the array to start
        public void DFT(byte[] s, int N, ref Complex[] amp, int start)
        {
            Complex tem = new Complex();
            int f;
            int t;

            for (f = 0; f < N; f++)
            {

                tem.real = 0;
                tem.im = 0;

                for (t = 0; t < N; t++)
                {
                    tem.real += s[t + start] * Math.Cos(2 * Math.PI * t * f / N);
                    tem.im -= s[t + start] * Math.Sin(2 * Math.PI * t * f / N);

                }
                amp[f].real = tem.real;
                amp[f].im = tem.im;

            }
        }

        //INVERSE FOURIER
        public void IDFT(Complex[] A, ref int[] s)
        {
            int N = A.Length;
            int t, f;
            double result;
            for (t = 0; t < N; t++)
            {
                result = 0;
                for (f = 0; f < N; f++)
                {
                    result += A[f].real * Math.Cos(2 * Math.PI * t * f / N) - A[f].im * Math.Sin(2 * Math.PI * t * f / N);
                }
                s[t] = (int)Math.Round(result);
            }
        }
    }
}

我现在非常困难,任何和所有的帮助都会受到赞赏。谢谢。

编辑:

这是我试图访问我所有课程的地方:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SoundEditor_V3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        string filename;
        NAudio.Wave.WaveStream waveStream;

        private NAudio.Wave.DirectSoundOut sout = null;

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {

            OpenFileDialog open = new OpenFileDialog();
            open.Filter = "Wave File (*.wav)|*.wav";
            if (open.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            waveStream = new NAudio.Wave.WaveFileReader(open.FileName);
            filename = open.FileName;
            sout = new NAudio.Wave.DirectSoundOut();
            sout.Init(new NAudio.Wave.WaveChannel32(waveStream));

        }

        //Play
        private void Play_btn_Click(object sender, EventArgs e)
        {
            sout.Play();
        }

        //Stop
        private void Stop_btn_Click(object sender, EventArgs e)
        {
            sout.Stop();
            waveStream.Position = 0;
        }

        //Pause
        private void Pause_btn_Click(object sender, EventArgs e)
        {
            sout.Pause();
        }



        //display fourier
        //N = number of samples(length of array)
        //s is the array of samples(data)
        //amp is the array where the complex result will be written to
        //start is the where in the array to start
        static int N = 8;
        byte[] s = {1,2,3,4,5,6,7,8};


        Complex[] amp = new Complex[N];

        Fourier xfo = new Fourier();



        //xfo.DFT(s, N,  amp, 0); 

    }
}

4 个答案:

答案 0 :(得分:1)

此调用应位于方法内。截至目前,它直接在一个类下面。

//xfo.DFT(s, N,  amp, 0);

同时为ref添加amp。 (因为void DFT(...., ref Complex[] amp,....)需要ref amp参数。

xfo.DFT(s, N, ref amp, 0);

答案 1 :(得分:1)

哦,男孩,还有很大的提升空间。

首先你使用Complex这个类作为结构,实际上它不需要成为一个类,所以把它变成一个结构:

public struct Complex
{
    public double Imaginary;
    public double Real;
}

不需要构造函数,默认构造函数(编译器添加)将根据类型将字段设置为默认值,对于double,默认值为0.0(这就是你无论如何都要分配给他们*)。

我还将im重命名为Imaginary,并且不要告诉我你必须输入更多因为你有智能感知。如果您没有下载Mono Develop或Visual Studio Express。哦,我能感受到你的想法:我们不应该继续使用这些工具。嗯,这是正确的,这是编写易于阅读的代码的另一个原因,即使对于那些不熟悉概念的人来说也是如此(这也使搜索更容易)。

*:我想要注意0是一个整数文字而0.0是双精度的,但编译器会重新对此进行重新计算并优化转换,因此实际上它是相同的。

让我们转到您的傅里叶类,首先是我在下面复制的方法DFT(复制字段的名称已重命名):

    //FOURIER
    //N = number of samples
    //s is the array of samples(data)
    //amp is the array where the complex result will be written to
    //start is the where in the array to start
    public void DFT(byte[] s, int N, ref Complex[] amp, int start)
    {
        Complex tem = new Complex();
        int f;
        int t;

        for (f = 0; f < N; f++)
        {

            tem.real = 0;
            tem.im = 0;

            for (t = 0; t < N; t++)
            {
                tem.real += s[t + start] * Math.Cos(2 * Math.PI * t * f / N);
                tem.im -= s[t + start] * Math.Sin(2 * Math.PI * t * f / N);
            }
            amp[f].real = tem.real;
            amp[f].im = tem.im;

        }
    }

首先要注意的是,你说N是样本数,s是样本数组。好吧,如果你有一个数组,你可以查询数组的大小,这是一个好主意,即使你想只允许处理数组的一部分(我想你想要那样)。但是,真的是N和s?

看,它就像魔术一样:

   //FOURIER
   //amp is the array where the complex result will be written to
   //start is the where in the array to start
   public void DFT(byte[] samples, int samplesCount, ref Complex[] amp, int start)
   {
       Complex tem = new Complex();
       int f;
       int t;

       for (f = 0; f < samplesCount; f++)
       {

           tem.Real = 0;
           tem.Imaginary = 0;

           for (t = 0; t < samplesCount; t++)
           {
               tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
               tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);
           }
           amp[f].Real = tem.Real;
           amp[f].Imaginary = tem.Imaginary;
       }
   }

好的,接下来你说amp是输出。好吧,如果它是输出,为什么你不做它的方法返回它?

的Bam!

   //FOURIER
   //start is the where in the array to start
   Complex[] DFT(byte[] samples, int samplesCount, int start)
   {
       var = new Complex[samplesCount];
       Complex tem = new Complex();
       int f;
       int t;
       for (f = 0; f < samplesCount; f++)
       {

           tem.Real = 0;
           tem.Imaginary = 0;

           for (t = 0; t < samplesCount; t++)
           {
               tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
               tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);
           }
           result[f].Real = tem.Real;
           result[f].Imaginary = tem.Imaginary;
       }
       return result;
   }

它真的需要是一个数组吗?我认为使用yield关键字并返回IEnumerable<Complex>是一个很好的机会。但是,我会以一种阵列的形式接受你想要的东西。

现在,您可能不希望返回数组。可能您只想修改预先存在的数组的部分。在这种情况下,你应该开始检查你的界限。即使这是真的,你也根本不需要参考!因为数组是引用类型。这是一个通过值传递的引用,如果你无法理解这个想法,只要相信我,你可以修改一个数组的内容,看看外面反映没有ref ...通过引用传递引用允许你改变引用另一个,你不是那样做的。

要说明:

void Main()
{
    var x = new int[1];
    Do(x);
    Console.WriteLine(x);
}

void Do (int[] array)
{
    array[0] = 1;
}

上一个程序的输出(使用LinqPad编译)是&#34; 1&#34;。

但是,让我们回到您的代码,是吗?

我不知道ft是什么。值得庆幸的是,我知道我是虚构的(是的,对吧?)。所以我不会重命名它们。但我会将他们的定义移到循环中:

   Complex[] DFT(byte[] samples, int samplesCount, int start)
   {
       var result = new Complex[samplesCount];
       Complex tem = new Complex();
       for (int f = 0; f < samplesCount; f++)
       {
           tem.Real = 0;
           tem.Imaginary = 0;
           for (int t = 0; t < samplesCount; t++)
           {
               tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
               tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);

           }
           result[f].Real = tem.Real;
           result[f].Imaginary = tem.Imaginary;
       }
       return result;
   }

请注意我使用var关键字。有了它,编译器会将变量的类型分配给我用来初始化它的类型。所以在这种情况下结果是Complex[],但我不必在代码中写两次。

最后,你复制Complex对象内容的部分,我也会改变它。为什么?因为Complex现在是一个结构体,结构体是值类型。因此,它的内容将被复制而不是引用。

   //FOURIER
   //start is the where in the array to start
   Complex[] DFT(byte[] samples, int samplesCount, int start)
   {
       var result = new Complex[samplesCount];
       Complex tem = new Complex();
       for (int f = 0; f < samplesCount; f++)
       {
           tem.Real = 0;
           tem.Imaginary = 0;
           for (int t = 0; t < samplesCount; t++)
           {
               tem.Imaginary += samples[t + start] * Math.Cos(2 * Math.PI * t * f / samplesCount);
               tem.Imaginary -= samples[t + start] * Math.Sin(2 * Math.PI * t * f / samplesCount);

           }
           result[f] = tem;
       }
       return result;
   }

我知道你真的想要只接受你阵列的一部分。但请耐心等待......你会学到一些东西,而且无论如何代码都会很有用。

我想要的下一件事是返回一个IEnumerable<Complex>,它是一个接口,表示可以迭代以获取Complex类型的对象的任何东西。我还会使用yield关键字。

此外,我已经摆脱了sampleCount并使用了samples.Length而不是。

看看它有多漂亮:

    //FOURIER
    public IEnumerable<Complex> DFT(byte[] samples, int startIndex)
    {
        int samplesLength = samples.Length;
        for (int f = 0; f < samplesLength; f++)
        {
            Complex resultItem = new Complex();
            for (int t = 0; t < samplesLength; t++)
            {
                resultItem.Real += samples[t + startIndex] * Math.Cos(2 * Math.PI * t * f / samplesLength);
                resultItem.Imaginary -= samples[t + startIndex] * Math.Sin(2 * Math.PI * t * f / samplesLength);
            }
            yield return resultItem;
        }
    }

事实上,我也会摆脱startIndex(我们不会检查边界*)。

*:也就是说,我们不检查索引是否在数组大小内。我知道,我知道,你以后会添加它们......可能。

无论如何,你在这里学习一些C#。

    //FOURIER
    public IEnumerable<Complex> DFT(byte[] samples)
    {
        int samplesLength = samples.Length;
        for (int f = 0; f < samplesLength; f++)
        {
            Complex resultItem = new Complex();
            for (int t = 0; t < samplesLength; t++)
            {
                resultItem.Real += samples[t] * Math.Cos(2 * Math.PI * t * f / samplesLength);
                resultItem.Imaginary -= samples[t] * Math.Sin(2 * Math.PI * t * f / samplesLength);
            }
            yield return resultItem;
        }
    }

好吧,困扰我的下一件事是傅立叶类没有状态(它没有字段,或者任何变量哪个值保持不变......)。因此,使用静态方法将其设为静态类:

public static class Fourier
{
    //FOURIER
    public static IEnumerable<Complex> DFT(byte[] samples)
    {
        int samplesLength = samples.Length;
        for (int f = 0; f < samplesLength; f++)
        {
            Complex resultItem = new Complex();
            for (int t = 0; t < samplesLength; t++)
            {
                resultItem.Real += samples[t] * Math.Cos(2 * Math.PI * t * f / samplesLength);
                resultItem.Imaginary -= samples[t] * Math.Sin(2 * Math.PI * t * f / samplesLength);
            }
            yield return resultItem;
        }
    }
}

当然你注意到我还没有添加IDFT。那是家庭作业。

现在,让我们看看你是如何使用它的。就我而言,我创建了一个ConsoleApplication,只是为了让它快速运行(没有浪费时间设计GUI)。

我想要的是调用Fourier.DFT,我可以在没有傅里叶类型的对象的情况下使用它,因为它是静态的(实际上我不能创建傅里叶类型的对象,因为它是静态的)。

此方法接收类型为byte[]的参数。那个将是new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }。并且该方法将返回我可以用来迭代以获取Complex类型的对象的东西。所以我想把它换成循环。

这就是我的代码的样子:

class Program
{
    static void Main(string[] args)
    {
        //display fourier
        foreach (var item in Fourier.DFT(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }))
        {
            Console.WriteLine(item);
        }
    }
}

现在......输出是......鼓声......

好吧,我无法看到它,我忘了Console.ReadLine();但是在添加输出后......

Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
Namespace.Complex
等等,什么?碰巧我还没有告诉它如何将Complex类型的对象转换为字符串。所以,让我们补充说:

public struct Complex
{
    public double Imaginary;
    public double Real;

    public override string ToString()
    {
        return string.Format("Complex [Real: {0}, Imaginary: {1}]", Real, Imaginary);
    }
}

现在我的输出是:

Complex [Real: 36, Imaginary: 0]
Complex [Real: -4, Imaginary: 9,65685424949238]
Complex [Real: -4, Imaginary: 4]
Complex [Real: -4, Imaginary: 1,65685424949239]
Complex [Real: -4, Imaginary: -3,91874033223161E-15]
Complex [Real: -4,00000000000001, Imaginary: -1,65685424949239]
Complex [Real: -4,00000000000002, Imaginary: -4,00000000000001]
Complex [Real: -3,99999999999997, Imaginary: -9,65685424949237]

输出是否正确?我没有吓人的想法!我必须更多地了解傅立叶(但看起来合法)。

验证后,输出正确。


最后一点注意事项:使用debuger逐步执行代码,您可能会发现一个惊喜(提示:收益)。

答案 2 :(得分:0)

你需要一个方法,试试这个:

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

namespace SoundEditor_V3
{
    public class Complex
    {
        public double real;
        public double im;

        public Complex()
        {
            real = 0;
            im = 0;
        }

        public Setval (double newReal, double newIm)
        {
            real = newReal;
            im = newIm;
        }
    }
}

关于你的其他课程,构造函数在哪里? ;)

答案 3 :(得分:0)

感谢您的帮助;我实际上最终搞清楚了一切。 我无法访问我试图访问它们的区域中的方法。我必须将它们放在方法块中,因为这些都是在表单内编码的。 无论如何,这是我的理解。

但是,再次感谢您的所有建议,他们都很有帮助。