是否可以使用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;
}
}
答案 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);
}
}