Let's say you have the following method:
public void Install()
{
CreateItem(Item1)
CreateItem(Item2)
CreateItem(Item3)
}
where CreateItem will throw a ItemAlreadyExistsException if the item already exists, but you want execution to continue to the other two even if that exception is thrown, so you'd probably do something similar to this:
public void Install()
{
var itemsColl = new[] {Item1, Item2, Item3};
foreach (var item in itemsColl)
{
try
{
CreateItem(item);
}
catch (ItemAlreadyExistsException e)
{
// Do nothing or handle exception
}
}
}
Now let's say you also have an Uninstall() method that does the opposite - deletes the items - and that you also have a Repair() method that just calls to Uninstall() and then Install() - with one small difference: on Repair() because you just had a call to Uninstall() before you calling Install() you know that the items should never exist (if they did, they would have gotten deleted by the Uninstall() call) which means now you do care about the ItemAlreadyExistsExceptions and you no longer want to catch them.
In this particular simple example the body of Install() is small/simple enough that it could just be copied to Repair() (although this would create duplication of code), but how would one go about creating something that works for a more complex example without creating duplication of code?
One thing I can think of is creating something like:
public void Install()
{
InternalInstall(false);
}
private void InternalInstall(bool throwOnError)
{
var itemsColl = new[] {Item1, Item2, Item3};
foreach (var item in itemsColl)
{
try
{
CreateItem(item);
}
catch (ItemAlreadyExistsException e)
{
if (throwOnError)
throw;
}
}
}
public void Repair()
{
Uninstall();
InternalInstall(true);
}
But having a parameter decide whether to throw or not is not a very good idea as stated here (even if this is a private method): Throw/do-not-throw an exception based on a parameter - why is this not a good idea?
Any other thoughts?
I think, I'd do it like this
IEnumerable<Item> Install(){
var failedItems = new List<Item>();
// assuming items is a list of Items on class level
foreach( var item in items )
{
try{ CreateItem(item); }
catch(ItemAlreadyExistsException ){
failedItems.Add(item);
}
}
return failedItems;
}
Something similar for Uninstall, and finally
IEnumerable<Item> Repair(){
var failedItems = new List<Item>();
// assuming items is a list of Items on class level
foreach( var item in items )
{
try
{
DeleteItem(item);
CreateItem(item);
}
catch(ItemAlreadyExistsException ){
failedItems.Add(item);
}
}
return failedItems;
}
Of course you immediately see where the code duplication is now and how you could improve from there on.
Maybe a little like this:
private IEnumerable<Item> GuardedIterationOfItems( Action<Item> action )
{
var failedItems = new List<Item>();
// assuming items is a list of Items on class level
foreach( var item in items )
{
try{
action(item);
}
catch(ItemAlreadyExistsException ){
failedItems.Add(item);
}
}
return failedItems;
}
IEnumerable<Item> Install()
{
return GuardedIterationOfItems( CreateItem );
}
IEnumerable<Item> UnInstall()
{
return GuardedIterationOfItems( DeleteItem );
}
IEnumerable<Item> Repair()
{
return GuardedIterationOfItems( x => {
DeleteItem(x);
CreateItem(x);
});
}
Disclaimer: Untested and maybe in need of threadsafety measures if it should be.
Related
What is the best approach in this scenario, where in there are multiple tasks that need to be run, depending on a given parameter. See the code below:
void Mapping()
{
if(param.IsProgram1) {
// spGetProgram1() is a stored procedure call
MapProgram1(context, spGetProgram1().GetIterator());
if(param.IsProgram2) {
MapProgram2(context, spGetProgram2().GetIterator());
}
}
if(param.IsProgram3) {
MapProgram3(context, spGetProgram23().GetIteratior());
}
}
static void MapProgram1(context, IEnumerable<IDataRecord> records) {
// map records to context
}
static void MapProgram2(context, IEnumerable<IDataRecord> records) {
// map records to context
}
static void MapProgram3(context, IEnumerable<IDataRecord> records) {
// map records to context
}
I want to refactor this and run the tasks in parallel. My current approach is that I store the task in a dictionary and invoke it depending on the given parameter
var tasks = new Dictionary<string, Task<IEnumerable<IDataRecord>>>()
{
{ "MapProgram1", null },
{ "MapProgram2", null },
{ "MapProgram3", null },
}
if(param.IsProgram1) tasks["MapProgram1"].Value = Task.Run(() => spGetProgram1().GetIterator())
... ...
tasks.WaitAll(tasks.Select(t => t.Value).ToArray());
And then fetch the result and call the corresponding mapping method like this
foreach(var t in tasks.Where(t => t.Value != null))
{
if(t.Key == "MapProgram1")
{
MapProgram1(context, t.Value.Result);
}
if (t.Key == "MapProgram2")
{
MapProgram2(context, t.Value.Result);
}
.....
}
I'm sure there's a cleaner approach on this, that I don't need to manually call the methods.
I'm not sure I followed your example; however, in general if you want to execute tasks in parallel and conditionally choose which tasks to execute, you might do something like this...
async Task Run() {
List<Task<IResult>> tasks = new List<Task<IResult>>();
if (someCondition) {
tasks.Add(RunSome(someParams));
}
if (othercondition) {
tasks.Add(RunOther(otherParam));
}
IResult[] results = await Task.WhenAll(tasks);
foreach (var result in results) {
if (result is SomeResult someResult) {
// Handle some result
}
else if (result is OtherResult otherResult) {
// Handle other result
}
}
}
static async Task<SomeResult> RunSome(someParams) {
// Run something
}
static async Task<OtherResult> RunOther(otherParams) {
// Run other thing
}
interface IResult {
}
class SomeResult : IResult {
}
class OtherResult: IResult {
}
You add the tasks you want to execute in parallel to a list, have each task return an instance of some result type, and then check the results after all tasks are completed.
You can do a lot with Parallel.ForEach i.e adjust the degree of parallelism, ect
However it does depend on your work load and what you are trying to achieve, however this may give you food for thought
var list = new List<Stuff>();
Parallel.ForEach(list, (item) =>
{
switch(item,ConditionType)
{
case ConditionType.First : DoSomethingWithItem(item); break;
case ConditionType.Second : DoSomethingElseWithItem(item); break;
}
});
More resources
Parallel.ForEach Method
Msdn : How to: Write a Simple Parallel.ForEach Loop
I have an ObservavebleColection bound to a listView. Basically, this collection must keep up with every change in the server and receives updates in string format.
My code parses the string and adds elements to the collection, but I'm having trouble finding a way to remove elements. How can I update the collection when an element is removed or changed on the server?
Here's my code:
public static ObservableCollection<TransactionDetails> offerList = new ObservableCollection<TransactionDetails>();
public async static Task<ObservableCollection<TransactionDetails>> getOfferList()
{
// Start getting Offers
string Offer = await BedpAPI_V1.getOfferList();
string[] splitedResponse = Offer.Split(new[] { "####" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string response in splitedResponse) {
string[] splitedMessage = response.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
offer.TransactionID = Convert.ToInt32(splitedMessage[0]);
offer.Seller = splitedMessage[1];
offer.Cost = Convert.ToDouble(splitedMessage[2]);
offer.Duration = Convert.ToInt16(splitedMessage[3]);
offer.Delay = Convert.ToInt16(splitedMessage[4]);
offer.Capacity = Convert.ToDouble(splitedMessage[5]);
offer.Availability = Convert.ToDouble(splitedMessage[6]);
if (currentOffer <= offer.TransactionID)
{
offerList.Add(new TransactionDetails() { TransactionID = offer.TransactionID, Seller = offer.Seller, Cost = offer.Cost, Duration = offer.Duration, Delay = offer.Delay, Capacity = offer.Capacity, Availability = offer.Availability });
currentOffer++;
}
}
return offerList;
}
If your ListView bind with a ObservavebleColection<>, when you modify an element, you may fire a OnCollectionChanged event yourself.
Assume you modify an element using []:
public class MyCollection : ObservableCollection<MyClass>
{
public new MyClass this[int index]
{
get { return base[index]; }
set
{
base[index] = value;
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
}
UPDATE:
Firstly, you may want to bind your collection like:
myCollection = MyFunction();
MyListView.ItemsSource = myCollection;
If you change an item in your collection like:
myCollection[index] = someNewItem;
Then you could update your listview like:
MyListView.Refresh();
But it is recommended to use some dynamic binding.
I solved the problem by clearing the collection on every call before parsing splitedResponse - as Clear() was throwing an unheld exception, had to handle it inside a throw catch block:
try
{
offerList.Clear();
}
catch (Exception ex) {
offerList.Clear();
Console.WriteLine(ex.Message);
}
im currently expanding my knowledge a little, and wanted to Create a little game for myself.
The Structure is as Following:
Programm.cs creates an instance of Gamecontroller. This Gamecontroller is the lowest level i want to Access. It will create instaces of the Views, and from classes like config.
I want to implement an debug Console with Command Input. These Commands should always start at the Gamecontroller level, and should be able to interact with kinda everything i could do with C# code.
So i want to access the Objects, Member and methods withing Gamecontroller, or Within any nested object.
Currently i cant get to the Properties of an Child, because _member returns an "Type" which gets parsed to RuntimeProperty instead of the Class
Example on Parsing:
"objPlayer.name" > "GameController.objPlayer.name"
"objConfig.someSetting = 10" > "GameController.objConfig.someSetting=10"
"objConfig.functionCall()" > "GameController.objConfig.functionCall()"
"objConfig.objPlayer.setName("someName")" > "GameController.objConfig.objPlayer.setName("someName")"
"objPlayer.name" > "GameController.objPlayer.name"
this is what i got so far:
private void parseComamnd(string Command)
{
var actions = Command.Split('.');
var start = this.GetType();
var last = actions[actions.Length - 1];
foreach (var action in actions)
{
if (action.Contains("(") && action.Contains(")"))
{
_exec(start, action);
}
else
{
start = _member(start, action);
}
}
}
private Type _member(Type pHandle, string pStrMember)
{
return pHandle.GetProperty(pStrMember).GetType();
}
private void _exec(Type pHandle, string pStrFunction)
{
var Regex = new Regex(#"\(|,|\)");
var FunctionParams = Regex.Split(pStrFunction);
var FunctionName = FunctionParams[0];
FunctionParams[0] = "";
FunctionParams = FunctionParams.Where(val => val != "").ToArray();
pHandle.GetMethod(FunctionName).Invoke(FunctionName, FunctionParams);
}
If I understood right, you want to match some string commands with actions you want to perform. In this case you could use Dictionary as a storage for string-delgate couples to match your string commands to actions you want to perform. As an advantage of this approach, you can change matched couples during program runtime as you wish
class SomeClass
{
delegate void OperationDelegate(string value);
IDictionary<string, OperationDelegate> Operations = new Dictionary<string, OperationDelegate>();
public SomeClass()
{
Operations.Add("objPlayer.name", SetName);
Operations.Add("objConfig.someSetting", SetSetting);
}
public void HandleNewValue(string command, string value)
{
try
{
if (Operations.ContainsKey(command))
Operations[command](value);
}
catch (Exception e)
{
Logger.Error(e);
}
}
private void SetName(string value)
{
// Some logic there
}
private void SetSetting(string value)
{
// Some logic there
}
}
When run conflict between class variables!
private myClass[] arrayms = new myClass[5];
foreach (myClass ms in arrayms) {
if (ms.ScheduleState)
Task.Factory.StartNew(() => ms.Start());
}
How can I run Several from a function at the same time from one class? C#
When run _StartTask() conflict between myClass variables and log result messy
private myClass[] arrayms = new myClass[5];
public void _TasksClassCreator()
{
foreach (var ms in arrayms )
{
ms.ScheduleName = SName;
.
.
.
}
}
public void _StartTask()
{
foreach (myClass ms in arrayms)
{
if (ms.ScheduleState)
Task.Factory.StartNew(() => ms.Start());
}
}
public sealed class myClass
{
public void Start()
{
_TBTask();
}
private void _TBTask()
{
while(true)
{
...//Conflict here
// this function always running and reporting result...
//log here
}
}
private string _ScheduleName;
public string ScheduleName
{
get
{
return _ScheduleName;
}
set
{
_ScheduleName = value;
}
.
.
.
}
}
I got a text summary, Classes are object. program do not have error, but only conflict variables when run. –
I don't understand "conflict variables". But the rest seems to fit what I described in my previous comment. i.e. the array is empty when calling foreach. So maybe this:
for (int i=0; i < ms.Length; i++) {
arrayms[i] = new MyClass();
}
// ScheduleState must somehow get set, then:
foreach (myClass ms in arrayms) {
if (ms.ScheduleState)
Task.Factory.StartNew(() => ms.Start());
}
edit
what does Task.Factory.StartNew(..) do? Its name StartNew implies that a new object is created and started. But an anonymous method that starts an existing object is passed. So are we actually starting two things here?
if this (comment, below) is not the problem then maybe it's the infamous scope problem when calling LINQ in a loop:
foreach (myClass ms in arrayms) {
MyClass workAround = ms; // must set "ms" to a loop-scoped variable.
// why? the answer is TL;DR
if (workAround.ScheduleState)
Task.Factory.StartNew(() => workAround.Start());
end edit
I have been trying to implement ISupportIncrementalLoading interface for an ObservableCollection. My implementation works for the most part but it behaves strangely under uncertain circumstances. Here is my code to IncrementalCollection class.
public class IncrementalCollection<T> : ObservableCollection<T>, ISupportIncrementalLoading
{
private bool hasMoreItems;
private int currentPage;
private string filter;
private Func<string, int, Task<IList<T>>> func;
Action onLoadingStarts;
Action onLoadingEnds;
public IncrementalCollection(Func<string, int, Task<IList<T>>> func, Action onLoadingStarts, Action onLoadingEnds)
{
this.func = func;
this.hasMoreItems = true;
this.onLoadingStarts = onLoadingStarts;
this.onLoadingEnds = onLoadingEnds;
}
public void ResetCollection(string filter)
{
currentPage = 0;
this.filter = filter;
this.Clear();
}
public bool HasMoreItems
{
get { return hasMoreItems; }
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
return DoLoadMoreItemsAsync(count).AsAsyncOperation<LoadMoreItemsResult>();
}
private async Task<LoadMoreItemsResult> DoLoadMoreItemsAsync(uint count)
{
onLoadingStarts();
var result = await func(this.filter, ++this.currentPage);
if (result == null || result.Count == 0)
{
hasMoreItems = false;
}
else
{
foreach (T item in result)
this.Add(item);
}
onLoadingEnds();
return new LoadMoreItemsResult() { Count = result == null ? 0 : (uint)result.Count };
}
}
The first strange behavior occurs when page loads, LoadMoreItemsAsync function is sometimes called once, generally twice and sometimes more than twice. This is strange as one call is enough to add enough items to the collection. I even tried to pull more data (2-3 times) but the behavior continues. There might be problem about the place of initialization of the IncrementalCollection object. As it seems the longer it takes to load the page the more calls are made to LoadMoreItemsAsync function. I am creating the collection in NavigationHelper_LoadState function like this.
_users = new IncrementalCollection<User>((filter, page) => _dataService.GetUserList(url, filter, null, page), onLoadingStarts, onLoadingEnds);
Second strange behavior is about caching, although I have added
this.NavigationCacheMode = NavigationCacheMode.Disabled;
to every page constructor and also changed NavigationHelper not to save pageState on back navigation. It feels like web requests are cached as it is very hard to return a response in that amount of time.
public void OnNavigatedFrom(NavigationEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back)
return;
var frameState = SuspensionManager.SessionStateForFrame(this.Frame);
var pageState = new Dictionary<String, Object>();
if (this.SaveState != null)
{
this.SaveState(this, new SaveStateEventArgs(pageState));
}
frameState[_pageKey] = pageState;
}
Any help about these strange behaviors is appreciated.
Also is there any good tutorial about ISupportIncrementalLoading interface that explains LoadMoreItemsAsync firing conditions. I am trying to modify a WrapPanel implementation but don't know where to start as I don't know what it looks for. This is probably about ItemHeight but still concrete information is better.
Thanks in advance.
There seems to be a bug in ISupportIncrementalLoading interface. Solved the multiple request problem by applying the solution here Create a ListView with LoadMoreItemsAsync on end of scroll.
I wrapped the foreach loop inside Task.WhenAll call.
await Task.WhenAll(Task.Delay(50), Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
foreach (T item in result)
this.Add(item);
}).AsTask());