Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用计时器访问另一个类中的成员?_C#_Pass By Reference - Fatal编程技术网

C# 如何使用计时器访问另一个类中的成员?

C# 如何使用计时器访问另一个类中的成员?,c#,pass-by-reference,C#,Pass By Reference,我目前正在编写一个类来计算在定义的时间段内的平均下载速度,使用定义数量的样本。我认为这样做的方式是,这个类运行一个Timer对象,它在所述类中调用一个方法,该方法将查看下载的字节(在父类FTPDownloadFile中维护),然后将该样本存储在队列中。然而,我的问题是访问下载的字节数 我访问这些信息的方法是通过在构建下载计算类时传入的引用,但是,似乎我没有正确理解/使用引用。传入的变量始终显示为0,即使我可以看到原始变量正在更改 有人能告诉我我做错了什么/为我提出一个更好的方法来完成我想做的事情

我目前正在编写一个类来计算在定义的时间段内的平均下载速度,使用定义数量的样本。我认为这样做的方式是,这个类运行一个Timer对象,它在所述类中调用一个方法,该方法将查看下载的字节(在父类FTPDownloadFile中维护),然后将该样本存储在队列中。然而,我的问题是访问下载的字节数

我访问这些信息的方法是通过在构建下载计算类时传入的引用,但是,似乎我没有正确理解/使用引用。传入的变量始终显示为0,即使我可以看到原始变量正在更改

有人能告诉我我做错了什么/为我提出一个更好的方法来完成我想做的事情吗

首先,下面是处理下载速度计算的类:

public class SpeedCalculator
    {
        private const int samples = 5;
        private const int sampleRate = 1000; //In milliseconds
        private int bytesDownloadedSinceLastQuery;
        private System.Threading.Timer queryTimer;
        private Queue<int> byteDeltas = new Queue<int>(samples);
        private int _bytesDownloaded;

        public SpeedCalculator(ref int bytesDownloaded)
        {
            _bytesDownloaded = bytesDownloaded;
        }

        public void StartPolling()
        {
            queryTimer = new System.Threading.Timer(this.QueryByteDelta, null, 0, sampleRate);
        }

        private void QueryByteDelta(object data)
        {
            if (byteDeltas.Count == samples)
            {
                byteDeltas.Dequeue();
            }

            byteDeltas.Enqueue(_bytesDownloaded - bytesDownloadedSinceLastQuery);
            bytesDownloadedSinceLastQuery = _bytesDownloaded;
        }

        /// <summary>
        /// Calculates the average download speed over a predefined sample size.
        /// </summary>
        /// <returns>The average speed in bytes per second.</returns>
        public float GetDownloadSpeed()
        {
            float speed;
            try
            {
                speed = (float)byteDeltas.Average() / ((float)sampleRate / 1000f);
            }
            catch {speed = 0f;}

            return speed;
        }
公共类速度计算器
{
私有常量int样本=5;
private const int sampleRate=1000;//以毫秒为单位
私有int字节下载SincellastQuery;
专用System.Threading.Timer查询器;
private Queue byteDeltas=新队列(样本);
下载的专用int_字节;
公共速度计算器(参考整数字节下载)
{
_bytesDownloaded=bytesDownloaded;
}
公开作废启动票()
{
queryTimer=new System.Threading.Timer(this.QueryByteDelta,null,0,sampleRate);
}
私有void QueryByteDelta(对象数据)
{
if(byteDeltas.Count==样本)
{
byteDeltas.Dequeue();
}
Enqueue(_bytesDownloaded-BytesDownloadedSincellastQuery);
BytesDownloadedSincellastQuery=\u bytesDownloaded;
}
/// 
///计算预定义样本大小上的平均下载速度。
/// 
///以字节/秒为单位的平均速度。
公共浮点GetDownloadSpeed()
{
浮动速度;
尝试
{
速度=(浮点)byteDeltas.Average()/(浮点)采样器/1000f);
}
捕捉{speed=0f;}
返回速度;
}
该类包含在我的FTPDownloadFile类中:

class FTPDownloadFile : IDisposable
{
    private const int recvBufferSize = 2048;
    public int bytesDownloaded;
    public SpeedCalculator Speed;
    private FileStream localFileStream;
    FtpWebResponse ftpResponse;
    Stream ftpStream;
    FtpWebRequest ftpRequest;
    public List<string> log = new List<string>();
    private FileInfo destFile;

    public event EventHandler ConnectionEstablished;

    public FTPDownloadFile()
    {
        bytesDownloaded = 0;
        Speed = new SpeedCalculator(ref bytesDownloaded);
    }

    public void GetFile(string host, string remoteFile, string user, string pass, string localFile)
    {
        //Some code to start the download...
        Speed.StartPolling();
    }

    public class SpeedCalculator {...}
}
类FTPDownloadFile:IDisposable
{
private const int recvBufferSize=2048;
公共int字节下载;
公共速度计算器速度;
私有文件流本地文件流;
FtpWebResponse-ftpResponse;
流;
FtpWebRequest ftpRequest;
公共列表日志=新列表();
私有文件信息文件;
已建立公共事件处理程序连接;
公共FTPDownloadFile()
{
字节数=0;
速度=新的速度计算器(参考字节下载);
}
public void GetFile(字符串主机、字符串远程文件、字符串用户、字符串传递、字符串本地文件)
{
//一些开始下载的代码。。。
速度。开始滑行();
}
公共类速度计算器{…}
}

这是理解C#中的“ref”参数的常见“问题”。您可以看到,与C+不同,C#中没有真正的值引用

<>在C++中,当你通过引用时,实际上内部将指针传递给变量。因此,可以有一个类成员变量,变量“int &”,这是对其他地方存储的整数的实际引用。 在C#中,“ref”或“out”参数的工作方式类似,但没有人谈论指针。您不能存储引用。您不能有“ref”类成员。看看您的类:sotrage变量的类型为“int”,普通为“int”,而不是引用

实际上,您是通过ref传递该值,但随后将其复制到成员变量中。“引用”在构造函数结束时消失

要了解它,您必须保留实际的源对象,或者通过接口引入强依赖项,或者通过委托引入弱依赖项,或者以惰性/功能性的方式进行

例1:强引用

public class SpeedCalculator
{
    private const int samples = 5;
    private const int sampleRate = 1000; //In milliseconds
    private int bytesDownloadedSinceLastQuery;
    private System.Threading.Timer queryTimer;
    private Queue<int> byteDeltas = new Queue<int>(samples);

    private FTPDownloadFile downloader; // CHANGE

    public SpeedCalculator(FTPDownloadFile fileDownloader) // CHANGE
    {
        downloader = fileDownloader;
    }

    public void StartPolling()
    {
        queryTimer = new System.Threading.Timer(this.QueryByteDelta, null, 0, sampleRate);
    }

    private void QueryByteDelta(object data)
    {
        if (byteDeltas.Count == samples)
        {
            byteDeltas.Dequeue();
        }

        byteDeltas.Enqueue(_bytesDownloaded - bytesDownloadedSinceLastQuery);

        bytesDownloadedSinceLastQuery = downloader.bytesDownloaded; // CHANGE
    }

//and in the other file

public FTPDownloadFile()
{
    bytesDownloaded = 0;
    Speed = new SpeedCalculator( this ); // CHANGE
}
public interface IByteCountSource
{
    int BytesDownloaded {get;}
}

public class FTPDownloadFile : IDisposable, IByteCountSource
{
    .....
    public int BytesDownloaded { get { return bytesDownloaded; } }
    .....

    public FTPDownloadFile()
    {
       bytesDownloaded = 0;
       Speed = new SpeedCalculator( this ); // note no change versus Ex#1 !
    }
}

public class SpeedCalculator
{
    ....

    private IByteCountSource bts;

    public SpeedCalculator(IByteCountSource countSource) // no "FTP" information!
    {
        this.bts = countSource;
    }

    ...

    private void QueryByteDelta(object data)
    {
        ....

        bytesDownloadedSinceLastQuery = bts.BytesDownloaded;
    }
第一个示例既快又脏。通常,我们希望类尽可能少地了解其他所有内容。那么为什么SpeedCalculator应该知道FTPDownloadFile?它需要知道的只是当前的字节数。因此,我引入了一个接口来“隐藏”后面的实际源代码。现在SpeedCalculator可以获取该值从实现接口的任何对象-无论是FTPDownloadFile、HTTPDownloadFile还是一些DummyTestDownloader

例3:委托、匿名函数等

public class SpeedCalculator
{
    ....

    private Func<int> bts;

    public SpeedCalculator(Func<int> countSource)
    {
        this.bts = countSource;
    }

    ...

    private void QueryByteDelta(object data)
    {
        ....

        bytesDownloadedSinceLastQuery = bts();
    }

// and in the other file

private int getbytes() { return bytesDownloaded; }

public FTPDownloadFile()
{
    bytesDownloaded = 0;
    Speed = new SpeedCalculator( this.getbytes ); // note it is NOT a getbytes() !
}

// or even

public FTPDownloadFile()
{
    bytesDownloaded = 0;
    Speed = new SpeedCalculator( () => this.bytesDownloaded ); // CHANGE
}
公共类速度计算器
{
....
私人Func基站;
公共速度计算器(Func countSource)
{
this.bts=countSource;
}
...
私有void QueryByteDelta(对象数据)
{
....
BytesDownloadedSincellastQuery=bts();
}
//在另一个文件中
private int getbytes(){return bytes;}
公共FTPDownloadFile()
{
字节数=0;
Speed=新的SpeedCalculator(this.getbytes);//注意它不是一个getbytes()!
}
//甚至
公共FTPDownloadFile()
{
字节数=0;
速度=新的速度计算器(()=>this.bytes下载);//更改
}
有接口的示例很漂亮,但接口很小。一个还可以,但有时需要引入几十个这样的一个属性或一个方法接口,这会变得有些枯燥和混乱。特别是如果所有这些都是“内部实现”,并且没有发布给任何其他人使用。您可以非常轻松地在第三个例子中,我用一个短lambda删除这样小的接口。我没有接收和存储一个实现接口的对象,而是将参数改为Func。这样我需要得到“一个返回INT的方法”。T