How to avoid modified closures with ThreadStart - c#

I'm getting an "Access to modified closure" error in Resharper. Is there a way to pass the task as a parameter to the lambda instead of relying upon a closure?
while (!Quitting && TaskQueue.Any())
{
foreach (var task in TaskQueue.ToArray())
{
if (Quitting || task.Code == TaskCode.Quit)
{
Quitting = true;
return;
}
if (!task.Runnable)
{
continue;
}
var thread = new Thread(() =>
{
try
{
task.Callback();
}
catch (Exception e)
{
if (task.Error != null)
{
task.Error(e);
}
}
});
thread.Start();
}
}

You could use the Thread.Start(object state) method:
while (!Quitting && TaskQueue.Any())
{
foreach (var task in TaskQueue.ToArray())
{
if (Quitting || task.Code == TaskCode.Quit)
{
Quitting = true;
return;
}
if (!task.Runnable)
{
continue;
}
var thread = new Thread(state =>
{
var taskState = (Task)state;
try
{
taskState.Callback();
}
catch (Exception e)
{
if (taskState.Error != null)
{
taskState.Error(e);
}
}
});
thread.Start(task);
}
}
which would have been equivalent to using a separate function:
private void Process(object state)
{
var task = (Task)state;
try
{
task.Callback();
}
catch (Exception e)
{
if (task.Error != null)
{
task.Error(e);
}
}
}
which you would have passed like that:
while (!Quitting && TaskQueue.Any())
{
foreach (var task in TaskQueue.ToArray())
{
if (Quitting || task.Code == TaskCode.Quit)
{
Quitting = true;
return;
}
if (!task.Runnable)
{
continue;
}
new Thread(this.Process).Start(task);
}
}

Related

Execute async await task WriteMultipleCoilsAsync issue

I could us some help getting the WriteMultipleCoilsAsync task to run. I'm getting the error message Cannot assign void to an implicitly-typed variable on the Task.Run statement. I need to capture the response message from WriteMultipleCoilsAsync.
Here the code:
private async void btnWriteMultipleCoils_Click(object? sender, EventArgs e)
{
string discretes = "true,false,true";
bool[] diarray = Array.ConvertAll(discretes.Split(','), bool.Parse);
var response = await Task.Run(() => master.WriteMultipleCoilsAsync(0, diarray));
await Task.CompletedTask;
}
Here is the WriteMultipleCoilsAsync task:
public Task WriteMultipleCoilsAsync(ushort startAddress, bool[] data)
{
return WriteMultipleCoilsAsync(0, startAddress, data);
}
Here is the WriteMultipleCoilsAsync task:
public Task WriteMultipleCoilsAsync(byte slaveAddress, ushort startAddress, bool[] data)
{
ValidateData("data", data, 1968);
WriteMultipleCoilsRequest request = new WriteMultipleCoilsRequest(slaveAddress, startAddress, new DiscreteCollection(data));
return PerformWriteRequestAsync<WriteMultipleCoilsResponse>(request);
}
Here is the PerformWriteRequestAsync Task:
private Task PerformWriteRequestAsync<T>(IModbusMessage request) where T : IModbusMessage, new()
{
return Task.Factory.StartNew(() => base.Transport.UnicastMessage<T>(request));
}
Here is the UnicastMessage method:
internal virtual T UnicastMessage<T>(IModbusMessage message) where T : IModbusMessage, new()
{
IModbusMessage modbusMessage = null;
int num = 1;
bool flag = false;
do
{
try
{
lock (_syncLock)
{
Write(message);
bool flag2;
do
{
flag2 = false;
modbusMessage = ReadResponse<T>();
SlaveExceptionResponse slaveExceptionResponse = modbusMessage as SlaveExceptionResponse;
if (slaveExceptionResponse != null)
{
flag2 = slaveExceptionResponse.SlaveExceptionCode == 5;
if (!flag2)
{
throw new SlaveException(slaveExceptionResponse);
}
Sleep(WaitToRetryMilliseconds);
}
else if (ShouldRetryResponse(message, modbusMessage))
{
flag2 = true;
}
}
while (flag2);
}
ValidateResponse(message, modbusMessage);
flag = true;
}
catch (SlaveException ex)
{
if (ex.SlaveExceptionCode != 6)
{
throw;
}
if (SlaveBusyUsesRetryCount && num++ > _retries)
{
throw;
}
Sleep(WaitToRetryMilliseconds);
}
catch (Exception ex2)
{
if (ex2 is FormatException || ex2 is NotImplementedException || ex2 is TimeoutException || ex2 is IOException)
{
if (num++ > _retries)
{
throw;
}
continue;
}
throw;
}
}
while (!flag);
return (T)modbusMessage;
}

How to reduce repeated code in foreach loop

if (!string.IsNullOrEmpty(View.Panel1.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN1 = View.Panel1;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
if (!string.IsNullOrEmpty(View.Panel2.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN2 = View.Panel2;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
if (!string.IsNullOrEmpty(View.Panel3.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN3 = View.Panel3;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
if (!string.IsNullOrEmpty(View.Panel4.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN4 = View.Panel4;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
if (!string.IsNullOrEmpty(View.Panel5.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN5 = View.Panel5;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
.....
.....
I have a foreach loop like above and i'm repeating the same code inorder to pass each panel value.
I'm trying to reduce the repeated code like below( but not sure it is correct way )
if (!string.IsNullOrEmpty(View.Panel1.ToString()))
{
setpanelinfo(View.Panel1.ToString(),PAN1)
}
if (!string.IsNullOrEmpty(View.Panel2.ToString()))
{
setpanelinfo(View.Panel2.ToString(),PAN2)
}
....
....
....
public void setpanelinfo(string strpanelvalue, string PAN)
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.+ "PAN1" = strpanelvalue; // ERROR
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
Is there a better way to write this above foreach logic with minimal code?
One approach to simplifying this is to use an Action callback for each specific case:
void HandlePanel(string panel, Action<OtherFeatures> action)
{
if (!string.IsNullOrEmpty(panel))
{
foreach (var of in FeaturesInfo)
{
if (of != null)
{
action(of);
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
}
...
HandlePanel(View.Panel1.ToString(), of => of.PAN1 = View.Panel1);
HandlePanel(View.Panel2.ToString(), of => of.PAN2 = View.Panel2);
HandlePanel(View.Panel3.ToString(), of => of.PAN3 = View.Panel3);
HandlePanel(View.Panel4.ToString(), of => of.PAN4 = View.Panel4);
....
Use the Controls collection of the form object:
(typecast)Controls(of+"PAN1").SomeProperty = some value;
I just think foreach-ing the collection three times is a little wasteful. Maybe something like this might be a little more performant
foreach (var of in FeaturesInfo)
{
if (of != null)
{
TestAndSet(View.Panel1.ToString(), text => of.PAN1 = text);
TestAndSet(View.Panel2.ToString(), text => of.PAN2 = text);
TestAndSet(View.Panel3.ToString(), text => of.PAN3 = text);
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
....
private void TestAndSet(String panel, Action<string> setAction)
{
if (!string.IsNullOrEmpty(panel))
{
setAction(panel);
}
}
In your case, you can do only one foreach and move the test inside of the loop.
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
if (!string.IsNullOrEmpty(View.Panel1.ToString()))
of.PAN1 = View.Panel1;
if (!string.IsNullOrEmpty(View.Panel2.ToString()))
of.PAN2 = View.Panel2;
if (!string.IsNullOrEmpty(View.Panel3.ToString()))
of.PAN3 = View.Panel3;
if (!string.IsNullOrEmpty(View.Panel4.ToString()))
of.PAN4 = View.Panel4;
if (!string.IsNullOrEmpty(View.Panel5.ToString()))
of.PAN5 = View.Panel5;
break;
}
}

Delete 3D Element from ObservableCollection

In my WPF 4.0 project, I have an ObservableCollection that contain some selected Visual3D from the view :
public ObservableCollection<Visual3D> SelectedElements
{
get { return _selectedElements; }
set
{
if (Equals(_selectedElements, value))
{
return;
}
_selectedElements = value;
RaisePropertyChanged(() => SelectedElements);
}
}
Visual3D elements are selected by clicking and the source-code in the VM is :
public HitTestResultBehavior HitTestDown(HitTestResult result)
{
var resultMesh = result as RayMeshGeometry3DHitTestResult;
if (resultMesh == null)
return HitTestResultBehavior.Continue;
// Obtain clicked ModelVisual3D.
var vis = resultMesh.VisualHit as ModelVisual3D;
if (vis != null)
{
Type visType = vis.GetType();
if (visType.Name == "TruncatedConeVisual3D" || visType.Name == "BoxVisual3D")
{
var geoModel = resultMesh.ModelHit as GeometryModel3D;
if (geoModel != null)
{
var selecteMat = geoModel.Material as DiffuseMaterial;
if (selecteMat != null) selecteMat.Brush.Opacity = selecteMat.Brush.Opacity <= 0.7 ? 1 : 0.7;
}
// Otherwise it's a chair. Get the Transform3DGroup.
var xformgrp = vis.Transform as Transform3DGroup;
// This should not happen, but play it safe anyway.
if (xformgrp == null)
{
return HitTestResultBehavior.Stop;
}
// Loop through the child tranforms.
foreach (Transform3D t in xformgrp.Children)
{
// Find the TranslateTransform3D.
var trans =
t as TranslateTransform3D;
if (trans != null)
{
// Define an animation for the transform.
var anima = new DoubleAnimation();
if (trans.OffsetY == 0)
{
DependencyProperty prop = TranslateTransform3D.OffsetZProperty;
if (Math.Abs(trans.OffsetZ) < 2)
{
anima.To = 20.5*Math.Sign(trans.OffsetZ);
Debug.Assert(SelectedElements != null, "SelectedElements != null");
}
else
{
anima.To = 1*Math.Sign(trans.OffsetZ);
SelectedElements.Add(vis);
}
// Start the animation and stop the hit-testing.
trans.BeginAnimation(prop, anima);
return HitTestResultBehavior.Stop;
}
}
}
}
}
return (HitTestResultBehavior) HitTestFilterBehavior.Continue;
}
and I want to delete one or all this Visual3D element
Thank you in advance
I have implemented this methode but it's not work :
private void UnloadProduct()
{
if (CanUnload)
{
foreach (Visual3D selectedElement in SelectedElements)
{
if (selectedElement.DependencyObjectType.Name == "TruncatedConeVisual3D")
{
var test = (TruncatedConeVisual3D) selectedElement;
int id = test.VisualId;
ElementsCollection.RemoveAt(id);
RaisePropertyChanged(() => ElementsCollection);
}
else
{
var test = (BoxVisual3D) selectedElement;
int id = test.VisualId;
ProductsCollection.RemoveAt(id);
}
}
}
}

Catch exception thrown in foreach condition

I have a foreach loop that breaks during the loop in the condition of the foreach itself. Is there a way to try catch the item that throws the exception and then continue the loop?
This will run a few times until the exception hits and then end.
try {
foreach(b in bees) { //exception is in this line
string += b;
}
} catch {
//error
}
This will not run at all because the exception is in the condition of the foreach
foreach(b in bees) { //exception is in this line
try {
string += b;
} catch {
//error
}
}
I know some of you are going to ask how this is happening so here is this:
Exception PrincipalOperationException is being thrown because a Principal (b in my example) cannot be found in GroupPrincipal (bees).
Edit: I added the code below. I also figured out that one group member was pointing to a domain that no longer exists. I easily fixed this by deleting the member but my question still stands. How do you handle exceptions that are thrown inside the condition of a foreach?
PrincipalContext ctx = new PrincipalContext(ContextType.domain);
GroupPrincipal gp1 = GroupPrincipal.FindByIdentity(ctx, "gp1");
GroupPrincipal gp2 = GroupPrincipal.FindByIdentity(ctx, "gp2");
var principals = gp1.Members.Union(gp2.Members);
foreach(Principal principal in principals) { //error is here
//do stuff
}
Almost the same as the answer from #Guillaume, but "I like mine better":
public static class Extensions
{
public static IEnumerable<T> TryForEach<T>(this IEnumerable<T> sequence, Action<Exception> handler)
{
if (sequence == null)
{
throw new ArgumentNullException("sequence");
}
if (handler == null)
{
throw new ArgumentNullException("handler");
}
var mover = sequence.GetEnumerator();
bool more;
try
{
more = mover.MoveNext();
}
catch (Exception e)
{
handler(e);
yield break;
}
while (more)
{
yield return mover.Current;
try
{
more = mover.MoveNext();
}
catch (Exception e)
{
handler(e);
yield break;
}
}
}
}
Maybe you can try to create a method like that:
public IEnumerable<T> TryForEach<T>(IEnumerable<T> list, Action executeCatch)
{
if (list == null) { executeCatch(); }
IEnumerator<T> enumerator = list.GetEnumerator();
bool success = false;
do
{
try
{
success = enumerator.MoveNext();
}
catch
{
executeCatch();
success = false;
}
if (success)
{
T item = enumerator.Current;
yield return item;
}
} while (success);
}
and you can use it this way:
foreach (var bee in TryForEach(bees.GetMembers(), () => { Console.WriteLine("Error!"); }))
{
}

UnobservedTaskException being throw but it is handled by a TaskScheduler.UnobservedTaskException handler and a continuations OnlyOnFaulted handler [duplicate]

This question already has answers here:
How to handle all unhandled exceptions when using Task Parallel Library?
(3 answers)
Closed 4 years ago.
I'm having problems with TPL programming.
I'm getting UnobservedTaskException while using #h4165f8ghd4f854d6f8h solution on [ http://stackoverflow.com/questions/7883052/a-tasks-exceptions-were-not-observed-either-by-waiting-on-the-task-or-accessi/11830087#11830087 ] to handle exceptions but still getting UnobservedTaskException.
I added the following code before starting tasks too:
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
e.SetObserved();
throw e.Exception;
};
but [ http://stackoverflow.com/questions/10874068/exception-thrown-in-task-thread-not-caught-by-unobservedtaskexception ] telling it won't catch every TPL unhandled exception.
I want propagate exceptions until reach top of stack then deal with it.
Can someone help me????
#Jon Skeet
Hi, I did a smaller repro, thanks for checking
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.tplTestOne();
}
public void tplTestOne()
{
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
e.SetObserved();
throw e.Exception;
};
Task tsk_1 = MyClassHere.createHandledTask(() =>
{
double x = 1;
x = (x + 1) / x;
}, false);
Task tsk_2 = MyClassHere.createHandledTask(() =>
{
double y = 0;
throw new Exception("forced_divisionbyzerodontthrowanymore_test"); // here -> System.Exception was unhandled by user code
}, true);
Task tsk_3 = MyClassHere.createHandledTask(() =>
{
double z = 1;
z = (z + 1) / z;
}, true);
Task tsk_4 = MyClassHere.createHandledTask(() =>
{
double k = 1;
k = (k + 1) / k;
}, true);
Console.ReadLine();
}
}
public static class MyClassHere
{
public static void waitForTsk(Task t)
{
try
{
t.Wait();
}
catch (AggregateException ae)
{
ae.Handle((err) =>
{
throw err;
});
}
}
public static void throwFirstExceptionIfHappens(this Task task)
{
task.ContinueWith(t =>
{
var aggException = t.Exception.Flatten();
foreach (var exception in aggException.InnerExceptions)
{
throw exception; // throw only first, search for solution
}
},
TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}
public static Task createHandledTask(Action action)
{
return createHandledTask(action, false);
}
public static Task createHandledTask(Action action, bool attachToParent)
{
Task tsk = null;
if (attachToParent)
{
TaskCreationOptions atp = TaskCreationOptions.AttachedToParent;
tsk = Task.Factory.StartNew(action, atp);
}
else
{
tsk = Task.Factory.StartNew(action);
}
tsk.throwFirstExceptionIfHappens();
return tsk;
}
}
Thanks
The solution was based on How to handle all unhandled exceptions when using Task Parallel Library?
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.tplTestOne();
}
public void tplTestOne()
{
//-------------------------------------------------
MyClassHere.onUnobservedTaskException += (object sender, EventException e) =>
{
Console.WriteLine(e.Exception.Message); //its fired OK
};
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs e) =>
{
Console.WriteLine(e.Exception.Message); // its not fired, buggy
};
//-------------------------------------------------
CancellationTokenSource source = new CancellationTokenSource();
Task tz = MyClassHere.CreateHandledTask(
new TaskScheduled(0, () => {
if (!source.IsCancellationRequested)
{
Console.WriteLine("A-main-task-started");
}
Thread.Sleep(5000);
if (source.IsCancellationRequested)
{
Console.WriteLine("CancelingMainTask");
}
})
, new TaskScheduled(3000, () => { Console.WriteLine("okTaskCalled"); })
, null //new TaskScheduled(0, () => { Console.WriteLine("cancelTaskCalled"); })
, TaskCreationOptions.AttachedToParent
, source.Token
, new TaskScheduled(2000, () =>
{
if (!source.IsCancellationRequested)
{
Console.WriteLine("B-timeout");
}
})
, new TaskScheduled(1000, () =>
{
if (!source.IsCancellationRequested)
{
Console.WriteLine("C-timeout");
}
source.Cancel();
})
);
if(tz != null)
{
tz.ContinueWith(t => { Console.WriteLine("END"); });
}
Task tsk_1 = MyClassHere.createHandledTask(() =>
{
double x = 1;
x = (x + 1) / x;
}, false);
Task tsk_2 = MyClassHere.createHandledTask(() =>
{
double y = 0;
throw new Exception("forced_divisionbyzerodontthrowanymore_test"); // here -> System.Exception was unhandled by user code
}, true);
Task tsk_3 = MyClassHere.createHandledTask(() =>
{
double z = 1;
z = (z + 1) / z;
}, true);
Task tsk_4 = MyClassHere.createHandledTask(() =>
{
double k = 1;
k = (k + 1) / k;
}, true);
Console.ReadLine();
}
}
public class EventException : EventArgs
{
public Exception Exception;
public Task task;
public EventException(Exception err, Task tsk)
{
Exception = err;
task = tsk;
}
}
public class TaskScheduled
{
public int waitTime;
public Action action;
public DateTime datestamp;
public bool isCalled = false;
public TaskScheduled(int _waitTime, Action _action)
{
this.waitTime = _waitTime;
this.action = _action;
}
}
public static class MyClassHere
{
public delegate void UnobservedTaskException(object sender, EventException e);
public static event UnobservedTaskException onUnobservedTaskException;
//-------------------------------------------------
public static void waitForTsk(Task t)
{
try
{
t.Wait();
}
catch (AggregateException ae)
{
ae.Handle((err) =>
{
throw err;
});
}
}
//-------------------------------------------------
public static void RaiseUnobsrvEvtForEachIfHappens(this Task task)
{
task.ContinueWith(t =>
{
var aggException = t.Exception.Flatten();
foreach (var exception in aggException.InnerExceptions)
{
onUnobservedTaskException(task, new EventException(exception, task));
}
},
TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}
//-------------------------------------------------
public static Task CreateHandledTask(Action action)
{
return CreateHandledTask(action, false);
}
public static Task CreateHandledTask(Action action, bool attachToParent)
{
Task tsk = null;
tsk = CreateHandledTask(action, attachToParent, CancellationToken.None);
return tsk;
}
public static Task CreateHandledTask(Action action, bool attachToParent, CancellationToken cancellationToken)
{
Task tsk = null;
TaskCreationOptions atp = TaskCreationOptions.None;
if (attachToParent) { atp = TaskCreationOptions.AttachedToParent; }
tsk = CreateHandledTask(action, atp, cancellationToken);
return tsk;
}
public static Task CreateHandledTask(Action action, TaskCreationOptions tco, CancellationToken cancellationToken)
{
Task tsk = null;
tsk = Task.Factory.StartNew(action, cancellationToken, tco, TaskScheduler.Default);
tsk.RaiseUnobsrvEvtForEachIfHappens();
return tsk;
}
public static Task CreateHandledTask(TaskScheduled mainTask,
TaskScheduled onSuccessTask,
TaskScheduled onCancelationTask,
TaskCreationOptions tco,
CancellationToken cancellationToken,
params TaskScheduled[] timeouts)
{
Task tsk = null;
ManualResetEvent me = new ManualResetEvent(false);
if (timeouts == null || timeouts.Length < 1 || timeouts[0] == null)
{
tsk = CreateHandledTask(mainTask.action, tco, cancellationToken);
me.Set();
}
else
{
bool isCancelation = false;
bool isSuccess = true;
Task NonBlockCtxTask = CreateHandledTask(() =>
{
tsk = CreateHandledTask(mainTask.action, tco, cancellationToken);
me.Set();
int qtdt = timeouts.Count(st => st.action != null);
CountdownEvent cde_pas = new CountdownEvent(3);
CountdownEvent cde_pat = new CountdownEvent(qtdt);
Parallel.ForEach<TaskScheduled>(timeouts, (ts) =>
{
try
{
bool itsOnTime = tsk.Wait(ts.waitTime, cancellationToken);
cde_pat.Signal();
if (!itsOnTime)
{
isSuccess = false;
Task tact = CreateHandledTask(ts.action, TaskCreationOptions.None, cancellationToken);
}
}
catch (OperationCanceledException oce)
{
isSuccess = false;
cde_pat.Signal(cde_pat.CurrentCount);
isCancelation = true;
}
});
try
{
isSuccess &= cde_pat.Wait(System.Threading.Timeout.Infinite, cancellationToken) && !isCancelation;
}
catch (OperationCanceledException oce)
{
isCancelation = true;
isSuccess = false;
}
finally
{
cde_pas.Signal();
}
try
{
if (isCancelation && onCancelationTask != null)
{
Thread.Sleep(onCancelationTask.waitTime);
Task tcn = CreateHandledTask(onCancelationTask.action);
}
}
catch { }
finally {
cde_pas.Signal();
}
try
{
if (isSuccess && onSuccessTask != null)
{
Thread.Sleep(onSuccessTask.waitTime);
Task tcn = CreateHandledTask(onSuccessTask.action);
}
}
catch { }
finally
{
cde_pas.Signal();
}
cde_pas.Wait(System.Threading.Timeout.Infinite);
}, TaskCreationOptions.None, cancellationToken);
}
me.WaitOne();
return tsk;
}
//-------------------------------------------------
}

Categories