C#/ GOTO就在这里吗?

时间:2011-07-06 20:08:24

标签: c# goto

哦,男孩,对C#中GOTO声明的热情;我甚至不敢问这个问题。

这么多类似的问题;这也让我有点紧张但我很认真。

请拒绝仅仅驳回批发GOTO声明的回复。

然而,我有点难以理解为什么这个实现不适合GOTO:

public event CancelEventHandler DeleteSnapshotStarted;
public event AsyncCompletedEventHandler DeleteSnapshotCompleted;
public void DeleteSnapshot(Guid documentId, Action<Exception> callback)
{
    if (!this.Snapshots.Where(x => x.DocumentId == documentId).Any())
        throw new Exception("Snapshot not found; ensure LoadSnapshots()");

    // define action
    var _Action = new Action(() =>
    {
        // preview
        bool _Cancelled = false;
        if (DeleteSnapshotStarted != null)
        {
            CancelEventArgs _CancelArgs = new CancelEventArgs { };
            DeleteSnapshotStarted(this, _CancelArgs);
            if (_CancelArgs.Cancel)
            {
                _Cancelled = true;
                goto END;
            }
        }

        // execute
        Exception _Error = null;
        try
        {
            Proxy.CoreService.DeleteSnapshot(documentId);
            LoadSnapshots(null);
        }
        catch (Exception ex) { _Error = ex; }

    END:

        // complete
        if (DeleteSnapshotCompleted != null)
        {
            AsyncCompletedEventArgs _CompleteArgs = 
                new AsyncCompletedEventArgs(_Error, _Cancelled, null);
            DeleteSnapshotCompleted(this, _CompleteArgs);
        }

        // bubble error
        if (_Error != null)
            throw _Error;
    });

    // run it
    if (callback == null) { _Action(); }
    else
    {
        using (BackgroundWorker _Worker = new BackgroundWorker())
        {
            _Worker.DoWork += (s, arg) => { _Action(); };
            _Worker.RunWorkerCompleted += (s, arg) => { callback(arg.Error); };
            _Worker.RunWorkerAsync();
        }
    }
}

**我给 - 我会避免GOTO! :d **

以下是最佳效果:

public event CancelEventHandler DeleteSnapshotStarted;
public event AsyncCompletedEventHandler DeleteSnapshotCompleted;
public void DeleteSnapshot(Guid documentId, Action<Exception> callback)
{
    if (!this.Snapshots.Where(x => x.DocumentId == documentId).Any())
        throw new Exception("Snapshot not found; ensure LoadSnapshots()");

    // define action
    var _Action = new Action(() =>
    {
        // preview
        CancelEventArgs _CancelArgs = new CancelEventArgs { };
        if (DeleteSnapshotStarted != null)
            DeleteSnapshotStarted(this, _CancelArgs);

        // execute
        Exception _Error = null;
        if (!_CancelArgs.Cancel) try
            {
                Proxy.CoreService.DeleteSnapshot(documentId);
                LoadSnapshots(null);
            }
            catch (Exception ex) { _Error = ex; }

        // complete
        if (DeleteSnapshotCompleted != null)
            DeleteSnapshotCompleted(this, 
              new AsyncCompletedEventArgs(null, _CancelArgs.Cancel, null));

        // bubble
        if (_Error != null)
            throw _Error;
    });

    // run it
    if (callback != null)
    {
        using (BackgroundWorker _Worker = new BackgroundWorker())
        {
            _Worker.DoWork += (s, arg) => { _Action(); };
            _Worker.RunWorkerCompleted += (s, arg) => 
                            { callback(arg.Error); };
            _Worker.RunWorkerAsync();
        }
    }
    else
        _Action();
}

谢谢大家。

11 个答案:

答案 0 :(得分:8)

是的,您甚至已经拥有了标志变量:

    if (!this.Snapshots.Where(x => x.DocumentId == documentId).Any())
        throw new Exception("Snapshot not found; ensure LoadSnapshots()");

    // define action
    var _Action = new Action(() =>
    {
        // preview
        bool _Cancelled = false;
        if (DeleteSnapshotStarted != null)
        {
            CancelEventArgs _CancelArgs = new CancelEventArgs { };
            DeleteSnapshotStarted(this, _CancelArgs);
            if (_CancelArgs.Cancel)
            {
                _Cancelled = true;
                goto END;
            }
        }

        if(!_Cancelled) {
            // execute
            Exception _Error = null;
            try
            {
                Proxy.CoreService.DeleteSnapshot(documentId);
                LoadSnapshots(null);
            }
            catch (Exception ex) { _Error = ex; }
        }
    END:

        // complete
        if (DeleteSnapshotCompleted != null)
        {
            AsyncCompletedEventArgs _CompleteArgs = 
                new AsyncCompletedEventArgs(_Error, _Cancelled, null);
            DeleteSnapshotCompleted(this, _CompleteArgs);
        }

        // bubble error
        if (_Error != null)
            throw _Error;
    });

答案 1 :(得分:4)

更改

        if (_CancelArgs.Cancel)
        {
            _Cancelled = true;
            goto END;
        }

到此:

_Cancelled = _CancelArgs.Cancel;

和END:对此:

if(!Cancelled)
{
   // complete...

答案 2 :(得分:3)

Neal Stephenson thinks it's cute to name his labels 'Dengo'

原则上,为了便于阅读,值得避免代码中的非本地分支。在您的情况下,可以使用标志变量重构控制流。有关详细信息,请参阅@NeilN和@minitech答案。

在实践中,有时候(在极少数情况下:)使用goto来解决复杂的控制场景流是很有用的,其中普通的if/else/break/while/for结构会比必要的更加嵌套或复杂。

goto(我现在能想到的)最好的“好”用法是打破一个深度嵌套的循环集,而不需要在每次循环迭代上进行额外的条件检查。从单一级别的嵌套中,您可以使用break - 但是对于许多嵌套级别,它会变得更加痛苦。这是一个例子:

// Column-ordered, first value search:
int valueFound = 0;
for (int i = 0; i < x; i++)
{
    for (int j = 0; j < y; j++)
    {
        if (array[j, i] < targetValue)
        {
            valueFound = array[j, i];
            goto Found;
        }
    }
}

Console.WriteLine("No value was found.");
return;

Found:
    Console.WriteLine("The number found was {0}.", valueFound);

答案 3 :(得分:2)

从它的外观来看,你可以用try/catch包裹if (!_Cancelled) { ... }。目前你拥有它的方式(从你提供的代码),你没有在任何地方使用_Cancelled。新代码如下:

public event CancelEventHandler DeleteSnapshotStarted;
public event AsyncCompletedEventHandler DeleteSnapshotCompleted;
public void DeleteSnapshot(Guid documentId, Action<Exception> callback)
{
    if (!this.Snapshots.Where(x => x.DocumentId == documentId).Any())
        throw new Exception("Snapshot not found; ensure LoadSnapshots()");

    // define action
    var _Action = new Action(() =>
    {
        // preview
        bool _Cancelled = false;
        if (DeleteSnapshotStarted != null)
        {
            CancelEventArgs _CancelArgs = new CancelEventArgs { };
            DeleteSnapshotStarted(this, _CancelArgs);
            if (_CancelArgs.Cancel)
            {
                _Cancelled = true;
            }
        }

        if (!_Cancelled) {
            // execute
            Exception _Error = null;
            try
            {
                Proxy.CoreService.DeleteSnapshot(documentId);
                LoadSnapshots(null);
            }
            catch (Exception ex) { _Error = ex; }
        }

        // complete
        if (DeleteSnapshotCompleted != null)
        {
            AsyncCompletedEventArgs _CompleteArgs = 
                new AsyncCompletedEventArgs(_Error, _Cancelled, null);
            DeleteSnapshotCompleted(this, _CompleteArgs);
        }

        // bubble error
        if (_Error != null)
            throw _Error;
    });

    // run it
    if (callback == null) { _Action(); }
    else
    {
        using (BackgroundWorker _Worker = new BackgroundWorker())
        {
            _Worker.DoWork += (s, arg) => { _Action(); };
            _Worker.RunWorkerCompleted += (s, arg) => { callback(arg.Error); };
            _Worker.RunWorkerAsync();
        }
    }
}

答案 4 :(得分:2)

为什么不在GOTO和标签之间的那些线周围if (!_Cancelled)

答案 5 :(得分:1)

一般来说: 相反,重构代码将更加清晰和可维护,因此不需要goto。这是一个很大的方法,应该分解一下。

偶尔goto是一个不错的选择,但很多时候,当简单的重构就足够了时,它会被使用。

在你的情况下: 在你的情况下,它似乎从很多其他答案建议使用取消的标志将解决你的问题没有goto。

答案 6 :(得分:1)

尝试用此包装删除快照并删除GOTOEND标签

if(!_Cancelled)
{
    Exception _Error = null;
        try
        {
            Proxy.CoreService.DeleteSnapshot(documentId);
            LoadSnapshots(null);
        }
        catch (Exception ex) { _Error = ex; }
}

答案 7 :(得分:0)

只需在if语句中使用已取消的变量,看看是否应该跳过剩下的代码。

答案 8 :(得分:0)

您的代码中不需要goto。它只会让它变得更复杂。这是没有它的等效版本。

public event CancelEventHandler DeleteSnapshotStarted;
public event AsyncCompletedEventHandler DeleteSnapshotCompleted;
public void DeleteSnapshot(Guid documentId, Action<Exception> callback)
{
    if (!this.Snapshots.Where(x => x.DocumentId == documentId).Any())
        throw new Exception("Snapshot not found; ensure LoadSnapshots()");

    // define action
    var _Action = new Action(() =>
    {
        // preview
        bool _Cancelled = false;
        if (DeleteSnapshotStarted != null)
        {
            CancelEventArgs _CancelArgs = new CancelEventArgs { };
            DeleteSnapshotStarted(this, _CancelArgs);
            if (_CancelArgs.Cancel)
            {
                _Cancelled = true;
            }
        }

        if (!_Cancelled) {
          // execute
          Exception _Error = null;
          try
          {
              Proxy.CoreService.DeleteSnapshot(documentId);
              LoadSnapshots(null);
          }
          catch (Exception ex) { _Error = ex; }
        }  

        // complete
        if (DeleteSnapshotCompleted != null)
        {
            AsyncCompletedEventArgs _CompleteArgs = 
                new AsyncCompletedEventArgs(_Error, _Cancelled, null);
            DeleteSnapshotCompleted(this, _CompleteArgs);
        }

        // bubble error
        if (_Error != null)
            throw _Error;
    });

    // run it
    if (callback == null) { _Action(); }
    else
    {
        using (BackgroundWorker _Worker = new BackgroundWorker())
        {
            _Worker.DoWork += (s, arg) => { _Action(); };
            _Worker.RunWorkerCompleted += (s, arg) => { callback(arg.Error); };
            _Worker.RunWorkerAsync();
        }
    }
}

答案 9 :(得分:0)

public event CancelEventHandler DeleteSnapshotStarted;
public event AsyncCompletedEventHandler DeleteSnapshotCompleted;
public void DeleteSnapshot(Guid documentId, Action<Exception> callback)
{
    if (!this.Snapshots.Where(x => x.DocumentId == documentId).Any())
        throw new Exception("Snapshot not found; ensure LoadSnapshots()");

    // define action
    var _Action = new Action(() =>
    {
        // preview
        bool _Cancelled = false;
        if (DeleteSnapshotStarted != null)
        {
            CancelEventArgs _CancelArgs = new CancelEventArgs { };
            DeleteSnapshotStarted(this, _CancelArgs);
            if (_CancelArgs.Cancel)
            {
                _Cancelled = true;
            }
        }

        if(!_Cancelled)
        {
            // execute
            Exception _Error = null;
            try
            {
                Proxy.CoreService.DeleteSnapshot(documentId);
                LoadSnapshots(null);
            }
            catch (Exception ex) { _Error = ex; }
        }

        // END:

        // complete
        if (DeleteSnapshotCompleted != null)
        {
            AsyncCompletedEventArgs _CompleteArgs = 
                new AsyncCompletedEventArgs(_Error, _Cancelled, null);
            DeleteSnapshotCompleted(this, _CompleteArgs);
        }

        // bubble error
        if (_Error != null)
            throw _Error;
    });

    // run it
    if (callback == null) { _Action(); }
    else
    {
        using (BackgroundWorker _Worker = new BackgroundWorker())
        {
            _Worker.DoWork += (s, arg) => { _Action(); };
            _Worker.RunWorkerCompleted += (s, arg) => { callback(arg.Error); };
            _Worker.RunWorkerAsync();
        }
    }
}

答案 10 :(得分:-1)

因为一个开关......休息可以让工作更干净。

您首先将CancleArgs声明为枚举{...已取消,...,END}

switch (CancleArgs)
 {
    case Canceled: _Cancelled = true; break;
 ... other stuff
    case END:
      { 
      // complete          
      if (DeleteSnapshotCompleted != null)          
       {              
         AsyncCompletedEventArgs _CompleteArgs = new AsyncCompletedEventArgs(_Error, _Cancelled, null);              
         DeleteSnapshotCompleted(this, _CompleteArgs);
       }            
      // bubble error          
      if (_Error != null) throw _Error;  
      }
      break;
 }
// run it
   ...

没有重构,因为它应该以这种方式开始编写。 ;)