使用Func类型而不是Silverlight中的Action进行代码简化

时间:2011-11-25 00:28:29

标签: c# silverlight asynchronous refactoring

是否可以使用Func类型而不是Action来重构此代码? 我想要的是摆脱用于通过Action回调返回值的额外Class(CalcParams)。

编辑: *注意:下载方法或Func应该是公开的;

非常感谢您的所有帮助。

public class CalcParams
{
    public int CallID;
    public int Result;
    public Action<int, int> CallbackDone;
    public CalcParams(int callid, Action<int, int> callback)
    {
        CallID = callid;
        CallbackDone = callback;
    }
}
public partial class MainPage : UserControl
{
    int rand;
    public MainPage()
    {
        InitializeComponent();
        rand = 0;
    }
    public void DownloadDataInBackground(CalcParams calcparams)
    {
        WebClient client = new WebClient();
        Uri uri = new Uri(string.Format("https://www.google.com/search?q={0}", calcparams.CallID));
        client.DownloadStringCompleted += (s, e) =>
        {
            CalcParams localparams = (CalcParams)e.UserState;
            localparams.CallbackDone(localparams.CallID, e.Result.Length);
        };
        client.DownloadStringAsync(uri, calcparams);
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        int callid = rand++;
        Debug.WriteLine("Executing CallID #{0}", callid);
        DownloadDataInBackground(new CalcParams(callid, (c, r) =>
        {
            Debug.WriteLine("The result for the callid {0} is {1}", c, r);
        }));
        callid = 0;
    }
}

4 个答案:

答案 0 :(得分:1)

不,不会。回调只是一种具有一些参数的方法。回调中返回值的功能是什么(Func只是一个带有返回值的动作)。在典型的情况下,你有理由不使用你的params类并直接传递所需的参数。

DownloadDataInBackground(int callId, Action<int, int> callback);

在类中包装参数可以使您的设计保持可维护性。由您决定何时使用类以及何时使用参数。

除此之外,你可以在DownloadDataInBackground中捕获calcparams,而不是必须使用userstate,例如:

答案 1 :(得分:1)

使用捕获功能可以非常优雅地避免添加其他类和/或使用userState

public partial class MainPage : UserControl
{
    Random rand;

    public MainPage()
    {
        InitializeComponent();
        rand = new Random();
    }

    public void DownloadDataInBackground(int callId, Action<int> returnResult)
    {
        WebClient client = new WebClient();
        Uri uri = new Uri("https://www.google.com/search?q=" + callId.ToString());
        client.DownloadStringCompleted += (s, e) =>
        {
            // Do something else with result ?
            returnResult(e.Result.Length);
        };
        client.DownloadStringAsync(uri);
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        int callid=rand.Next();
        Debug.WriteLine("Executing CallID #{0}", callid);
        DownloadDataInBackground(callid, r =>
        {
            Debug.WriteLine("The result for the callid {0} is {1}", callid, r);
        }));
    }
}

请注意,现在只需要Action<int>,点击事件中的callid将被“捕获”,以便在returnResult回调中使用。

答案 2 :(得分:1)

基于你给出的评论,我建议你使用TPL而不是你自己的回调,这会让生活更轻松:)(现在你没有任何异常处理)。在ParallelExtensionsExtra的项目以及.NET 4.5中,您将找到另一个名为DownloadStringTask的webclient,它返回一个任务。假设您没有使用它,您可以轻松复制它。请检查以下代码:

    public Task<string> DownloadDataInBackground(int id)
    {
        TaskCompletionSource<string> resultTaskCompletionSource = new TaskCompletionSource<string>(id);

        WebClient client = new WebClient();

        Uri uri = new Uri(string.Format("https://www.google.com/search?q={0}", id));
        client.DownloadStringCompleted += (s, e) =>
        {
            if (e.Error != null)
                resultTaskCompletionSource.SetException(e.Error);
            else if (e.Cancelled)
                resultTaskCompletionSource.SetCanceled();
            else
                resultTaskCompletionSource.SetResult(e.Result);

        };
        client.DownloadStringAsync(uri);

        return resultTaskCompletionSource.Task;
    }


    private void button1_Click(object sender, EventArgs e)
    {
        int callid = rand++;
        Debug.WriteLine("Executing CallID #{0}", callid);

        DownloadDataInBackground(callid).ContinueWith(task =>
        {
            if (task.IsCompleted)
            {
                Debug.WriteLine("Download for {0} completed with a length of {1}", task.AsyncState, task.Result.Length);
            }
        });
    }

答案 3 :(得分:0)

这是我的第一种方法,我想知道另一种更简单或更清洁的方法。

public partial class MainPage : UserControl
{
    int rand;
    public MainPage()
    {
        InitializeComponent();
        rand = 0;
    }

    public Func<Action<int, int>, Action<int>> DownloadDataInBackground = (callback) =>
    {
        return (c) =>
        {
            WebClient client = new WebClient();
            Uri uri = new Uri(string.Format("https://www.google.com/search?q={0}", c));
            client.DownloadStringCompleted += (s, e2) =>
            {
                callback(c, e2.Result.Length);
            };
            client.DownloadStringAsync(uri);
        };
    };

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        int callid = rand++;
        Debug.WriteLine("Executing CallID #{0}", callid);
        DownloadDataInBackground((c3, r3) =>Debug.WriteLine("The result for the callid {0} is {1}", c3, r3))(callid);
    }
}