C#自动重置事件未释放
使用Xamarin.Forms(用于iOS)我尝试实现功能,以等待用户确认已设置地理位置权限,然后再继续 我试图实现这一点的方法是让线程等待,直到使用C#自动重置事件未释放,c#,ios,xamarin,autoresetevent,C#,Ios,Xamarin,Autoresetevent,使用Xamarin.Forms(用于iOS)我尝试实现功能,以等待用户确认已设置地理位置权限,然后再继续 我试图实现这一点的方法是让线程等待,直到使用AutoResetEvent触发事件 主要问题(我相信)在于以下代码: manager.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs args) => { Console.WriteLine ("Authorization change
AutoResetEvent
触发事件
主要问题(我相信)在于以下代码:
manager.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs args) => {
Console.WriteLine ("Authorization changed to: {0}", args.Status);
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
tcs.SetResult (args.Status == CLAuthorizationStatus.AuthorizedAlways || args.Status == CLAuthorizationStatus.AuthorizedWhenInUse);
} else {
tcs.SetResult (args.Status == CLAuthorizationStatus.Authorized);
}
_waitHandle.Set ();
};
manager.Failed += (object sender, Foundation.NSErrorEventArgs e) => {
Console.WriteLine ("Authorization failed");
tcs.SetResult (false);
_waitHandle.Set ();
};
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
manager.RequestWhenInUseAuthorization ();
}
_waitHandle.WaitOne ();
您可以在下面找到完整的类:
public class LocationManager : ILocationManager
{
static EventWaitHandle _waitHandle = new AutoResetEvent (false);
private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
public LocationManager ()
{
}
public Task<bool> IsGeolocationEnabledAsync()
{
Console.WriteLine (String.Format("Avaible on device: {0}", CLLocationManager.LocationServicesEnabled));
Console.WriteLine (String.Format("Permission on device: {0}", CLLocationManager.Status));
if (!CLLocationManager.LocationServicesEnabled) {
tcs.SetResult (false);
} else if (CLLocationManager.Status == CLAuthorizationStatus.Denied || CLLocationManager.Status == CLAuthorizationStatus.Restricted) {
tcs.SetResult (false);
} else if (CLLocationManager.Status == CLAuthorizationStatus.NotDetermined) {
Console.WriteLine ("Waiting for authorisation");
CLLocationManager manager = new CLLocationManager ();
manager.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs args) => {
Console.WriteLine ("Authorization changed to: {0}", args.Status);
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
tcs.SetResult (args.Status == CLAuthorizationStatus.AuthorizedAlways || args.Status == CLAuthorizationStatus.AuthorizedWhenInUse);
} else {
tcs.SetResult (args.Status == CLAuthorizationStatus.Authorized);
}
_waitHandle.Set ();
};
manager.Failed += (object sender, Foundation.NSErrorEventArgs e) => {
Console.WriteLine ("Authorization failed");
tcs.SetResult (false);
_waitHandle.Set ();
};
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
manager.RequestWhenInUseAuthorization ();
}
_waitHandle.WaitOne ();
Console.WriteLine (String.Format ("Auth complete: {0}", tcs.Task.Result));
} else {
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
tcs.SetResult (CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse);
} else {
tcs.SetResult (CLLocationManager.Status == CLAuthorizationStatus.Authorized);
}
}
return tcs.Task;
}
}
公共类位置管理器:ILocationManager
{
静态EventWaitHandle _waitHandle=new AutoResetEvent(false);
私有TaskCompletionSource tcs=新TaskCompletionSource();
公共场所经理()
{
}
公共任务IsGeolocationEnabledAsync()
{
Console.WriteLine(String.Format(“在设备上可用:{0}”,CLLocationManager.LocationServicesEnabled));
Console.WriteLine(String.Format(“设备上的权限:{0}”,CLLocationManager.Status));
如果(!CLLocationManager.LocationServicesEnabled){
tcs.SetResult(假);
}else if(CLLocationManager.Status==CLAuthorizationStatus.Denied | | CLLocationManager.Status==CLAuthorizationStatus.Restricted){
tcs.SetResult(假);
}else if(CLLocationManager.Status==CLAuthorizationStatus.NotDetermined){
Console.WriteLine(“等待授权”);
CLLocationManager=newcllocationmanager();
manager.AuthorizationChanged+=(对象发送方、CLAuthorizationChangedEventArgs)=>{
Console.WriteLine(“授权更改为:{0}”,args.Status);
if(UIDevice.CurrentDevice.CheckSystemVersion(8,0)){
tcs.SetResult(args.Status==CLAuthorizationStatus.authorizedAllways | | args.Status==CLAuthorizationStatus.AuthorizedWhenInUse);
}否则{
tcs.SetResult(args.Status==CLAuthorizationStatus.Authorized);
}
_Set();
};
失败的+=(对象发件人,基础.nSerrReErrARGES E)= > {
Console.WriteLine(“授权失败”);
tcs.SetResult(假);
_Set();
};
if(UIDevice.CurrentDevice.CheckSystemVersion(8,0)){
manager.requestwhenUseAuthorization();
}
_waitHandle.WaitOne();
Console.WriteLine(String.Format(“Auth complete:{0}”,tcs.Task.Result));
}否则{
if(UIDevice.CurrentDevice.CheckSystemVersion(8,0)){
tcs.SetResult(CLLocationManager.Status==CLAuthorizationStatus.AuthorizedAlways | | CLLocationManager.Status==CLAuthorizationStatus.AuthorizedWhenInUse);
}否则{
tcs.SetResult(CLLocationManager.Status==CLAuthorizationStatus.Authorized);
}
}
返回tcs.Task;
}
}
它工作正常,只是我不明白为什么manager.AuthorizationChanged
或manager.Failed
事件似乎永远不会被触发,因此当状态未确定时,线程永远不会释放
非常感谢您的任何帮助或指点。如果没有这些帮助或指点,您将无法确定问题所在。但是你的代码中肯定有一个明显的设计缺陷,我希望解决这个缺陷能解决你的问题
有什么缺点?你在等待任何事情。您编写了一个显然应该表示异步操作的方法-它的名称中有“Async”,并返回一个Task
,而不是bool
-然后您以这样一种方式编写该方法:返回的Task
将始终完成,而不管采用哪种代码路径
为什么这么糟糕?好的,除了完全无法利用您正在实现的接口的异步方面这一简单事实之外,您正在使用的CLLocationManager
类很可能希望能够在调用IsGeolocationEnabledAsync()
方法的同一线程中运行。由于此方法在引发事件之前不会返回,并且在方法返回之前无法引发事件,因此存在死锁
IMHO,这就是你的类应该如何实现的:
public class LocationManager : ILocationManager
{
public async Task<bool> IsGeolocationEnabledAsync()
{
bool result;
Console.WriteLine (String.Format("Avaible on device: {0}", CLLocationManager.LocationServicesEnabled));
Console.WriteLine (String.Format("Permission on device: {0}", CLLocationManager.Status));
if (!CLLocationManager.LocationServicesEnabled) {
result = false;
} else if (CLLocationManager.Status == CLAuthorizationStatus.Denied || CLLocationManager.Status == CLAuthorizationStatus.Restricted) {
result = false;
} else if (CLLocationManager.Status == CLAuthorizationStatus.NotDetermined) {
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Console.WriteLine ("Waiting for authorisation");
CLLocationManager manager = new CLLocationManager ();
manager.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs args) => {
Console.WriteLine ("Authorization changed to: {0}", args.Status);
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
tcs.SetResult (args.Status == CLAuthorizationStatus.AuthorizedAlways || args.Status == CLAuthorizationStatus.AuthorizedWhenInUse);
} else {
tcs.SetResult (args.Status == CLAuthorizationStatus.Authorized);
}
};
manager.Failed += (object sender, Foundation.NSErrorEventArgs e) => {
Console.WriteLine ("Authorization failed");
tcs.SetResult (false);
};
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
manager.RequestWhenInUseAuthorization ();
result = await tcs.Task;
} else {
result = false;
}
Console.WriteLine (String.Format ("Auth complete: {0}", tcs.Task.Result));
} else {
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
result = CLLocationManager.Status == CLAuthorizationStatus.AuthorizedAlways || CLLocationManager.Status == CLAuthorizationStatus.AuthorizedWhenInUse;
} else {
result = CLLocationManager.Status == CLAuthorizationStatus.Authorized;
}
}
return result;
}
}
公共类位置管理器:ILocationManager
{
公共异步任务IsGeolocationEnabledAsync()
{
布尔结果;
Console.WriteLine(String.Format(“在设备上可用:{0}”,CLLocationManager.LocationServicesEnabled));
Console.WriteLine(String.Format(“设备上的权限:{0}”,CLLocationManager.Status));
如果(!CLLocationManager.LocationServicesEnabled){
结果=假;
}else if(CLLocationManager.Status==CLAuthorizationStatus.Denied | | CLLocationManager.Status==CLAuthorizationStatus.Restricted){
结果=假;
}else if(CLLocationManager.Status==CLAuthorizationStatus.NotDetermined){
TaskCompletionSource tcs=新的TaskCompletionSource();
Console.WriteLine(“等待授权”);
CLLocationManager=newcllocationmanager();
manager.AuthorizationChanged+=(对象发送方、CLAuthorizationChangedEventArgs)=>{
Console.WriteLine(“授权更改为:{0}”,args.Status);
if(UIDevice.CurrentDevice.CheckSystemVersion(8,0)){
tcs.SetResult(args.Status==CLAuthorizationStatus.authorizedAllways | | args.Status==CLAuthorizationStatus.AuthorizedWhenInUse);
}否则{
tcs.SetResult(args.Status==CLAuthorizationStatus.Authorized);
}
};
失败的+=(对象发件人,基础.nSerrReErrARGES E)= > {
Console.WriteLine(“Auth