Нужно объяснение по этому коду - c # - PullRequest
3 голосов
/ 14 апреля 2010

Я знакомлюсь с C # изо дня в день, и я наткнулся на этот кусок кода

public static void CopyStreamToStream(
Stream source, Stream destination, 
Action<Stream,Stream,Exception> completed) {
byte[] buffer = new byte[0x1000];
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(null);

Action<Exception> done = e => {
    if (completed != null) asyncOp.Post(delegate { 
        completed(source, destination, e); }, null);
};

AsyncCallback rc = null;
rc = readResult => {
    try {
        int read = source.EndRead(readResult);
        if (read > 0) {
            destination.BeginWrite(buffer, 0, read, writeResult => {
                try {
                    destination.EndWrite(writeResult);
                    source.BeginRead(
                        buffer, 0, buffer.Length, rc, null);
                }
                catch (Exception exc) { done(exc); }
            }, null);
        }
        else done(null);
    }
    catch (Exception exc) { done(exc); }
};

source.BeginRead(buffer, 0, buffer.Length, rc, null);

}

Из этой статьи Статья

Что я не могу понять, так это то, как делегат получает уведомление о том, что копия сделана?Скажем, после того, как копия сделана, я хочу выполнить операцию над скопированным файлом.

И да, я действительно знаю, что это может превзойти меня, учитывая мои несколько лет в C #.

Ответы [ 4 ]

5 голосов
/ 14 апреля 2010

The

done(exc);

и

else done(null);

биты выполняют Action<Exception>, что, в свою очередь, вызывает Action<Stream, Stream, Exception>, переданное в него с использованием параметра completed.

Это делается с помощью AsyncOperation.Post, поэтому делегат completed выполняется в соответствующем потоке.

РЕДАКТИРОВАТЬ: Вы бы использовали что-то вроде этого:

CopyStreamToStream(input, output, CopyCompleted);
...

private void CopyCompleted(Stream input, Stream output, Exception ex)
{
    if (ex != null)
    {
        LogError(ex);
    }
    else
    {
        // Put code to notify the database that the copy has completed here
    }
}

Или вы можете использовать лямбда-выражение или анонимный метод - это зависит от того, сколько логики вам нужно.

2 голосов
/ 14 апреля 2010

Делегат помещается в другой делегат с именем done. Это вызывается в блоках catch, а также в блоке else ближе к концу делегата AsyncCallback, который, в свою очередь, передается в BeginRead:

AsyncCallback rc = null;
rc = readResult => {
    try {
        int read = source.EndRead(readResult);
        if (read > 0) {
            destination.BeginWrite(buffer, 0, read, writeResult => {
                try {
                    destination.EndWrite(writeResult);
                    source.BeginRead(
                        buffer, 0, buffer.Length, rc, null);
                }
                catch (Exception exc) { done(exc); }  // <-- here
            }, null);
        }
        else done(null);   // <-- here
    }
    catch (Exception exc) { done(exc); }   // <-- and here
};
1 голос
/ 14 апреля 2010

Строки done(...) - это место, где поднимается делегат. Делегат назначается ранее в коде, т.е.

Action<Exception> done = e => {  
    if (completed != null) asyncOp.Post(delegate {   
        completed(source, destination, e); }, null);  
};  
0 голосов
/ 15 апреля 2010

@ ltech - Могу ли я использовать это для копирования нескольких файлов на сервере? пример: в цикле for Могу ли я вызвать этот метод, и будет ли он аналогичен созданию экземпляров потоков или вызову делегата через шаблон команды для перемещения нескольких файлов?

...