depending on the do work method my result could either be a List of Strings or a list of byte[]
How can we check the RunWorkerCompletedEventArgs e -
if (e is List<String>)
is this the correct way to check?
No, this is not the right way.
The correct way is to use this:
if(e.Result is List<string>)
{
//...
}
else if(e.Result is List<byte[]>)
{
//...
}
else
{
//...
}
e will always be of type RunWorkerCompletedEventArgs. But this class contains a property Result that contains the result of your DoWork event handler. That's the one, you need to check.
Yes, that's one possible way to do it.
If you only have two types it would be quite easy:
if(e.Result is List<string>)
{
}
else if(e.Result is List<byte[]>)
{
}
else
{
}
But the problem comes in to play if you have to support more than just two or three. In that case i'm going to create a Dictionary<Type, Action<object>> and write individual functions for each type. Something like this:
var supportedTypes = new Dictionary<Type, Action<object>>();
supportedTypes.Add(typeof(List<string>), ComputeListOfStrings);
supportedTypes.Add(typeof(List<byte[]>), ComputeListOfByteArrays);
private void ComputeListOfString(object listOfStrings)
{
var list = (List<string>)listOfStrings;
}
private void ComputeListOfByteArrays(object listOfByteArrays)
{
var list = (List<byte[]>)listOfByteArrays;
}
This makes it more simple to support new types and also stays to be O(1) while the if-else-if runs into the order-matters problem.
Used will this in your background worker as followed:
worker.OnRunWorkerCompleted += (sender, e) =>
{
Action<object> supportedAction;
supportedTypes.TryGetValue(e.Result.GetType(), out supportedAction);
if(supportedAction != null)
{
supportedAction();
}
};
the e.Result is the property with your results, so to get the type you can do:
if(e.Result.GetType().Equals(typeof(List<String>)))
Related
I want to instantiate an object and change/set a variable inside an array with a short (for efficiency purposes) amount of code, but this doesn't work:
private ClickBox[] clickBoxes = new ClickBox[]
{
new ClickBox().OnClick += (#object) =>
{
}
};
class ClickBox
{
public delegate void ClickEvent(Object #object);
private ClickEvent clickEvent;
public ClickEvent OnClick
{
get { return clickEvent; }
set { clickEvent = value; }
}
}
Does anyone know a way to return the object instead of the variable in this code? I know it would work to set the ClickEvent after the array is made, but this would be very inefficient for a large number of items.
Thank you.
You should really write a builder method to implement this.
Something really simple could look like this:
static ClickBox createClickBox(Action<ClickBox> subscribe)
{
var result = new ClickBox();
subscribe(result);
return result;
}
You could use that to initialise an array that is a field of the class like so:
readonly ClickBox[] clickBoxes =
{
createClickBox(cb => cb.OnClick += o => { /* Code 1 */ }),
createClickBox(cb => cb.OnClick += o => { /* Code 2 */ })
};
But I must agree with others who say this is a bit of a code smell - although without more context about how you really intend to use this, it's hard to say for sure.
Also, when talking about efficiency: I assume you are talking in terms of reducing the number of lines of code, rather than performance.
Before C#6, i was using this routine to deal with generating events in a multi threaded program: (i found it somewhere, but can't remember where):
public static object Raise(this MulticastDelegate multicastDelegate, object sender, EventArgs e)
{
object retVal = null;
MulticastDelegate threadSafeMulticastDelegate = multicastDelegate;
if (threadSafeMulticastDelegate != null)
{
foreach (Delegate d in threadSafeMulticastDelegate.GetInvocationList())
{
var synchronizeInvoke = d.Target as ISynchronizeInvoke;
if ((synchronizeInvoke != null) && synchronizeInvoke.InvokeRequired)
retVal = synchronizeInvoke.EndInvoke(synchronizeInvoke.BeginInvoke(d, new[] { sender, e }));
else
retVal = d.DynamicInvoke(sender, e);
}
}
return retVal;
}
so all i had to do was Eventname.Raise(...,....)
now with C#6, i know the new was it using something like:
Eventname?.Invoke(...);
what i am wondering is, should i change all my event creations to Invoke as it works different to the Raise(), or is it the same thing ?
You should never have been using that method in the first place. It's way too complicated. Instead, something like this would have been better:
public static void Raise(this Delegate handler, object sender, EventArgs e)
{
if (handler != null)
{
handler.DynamicInvoke(sender, e);
}
}
As for whether you should change your event-raising code, I'd say no. Not unless you've got a lot of time to kill and like going through your entire code base replacing perfectly good code.
What you should do is fix your current Raise() method. And feel free for any new code to write it the new C# 6 way, i.e. MyEvent?.DynamicInvoke(this, EventArgs.Empty) (which effectively amounts to the exact same thing as MyEvent.Raise(this, EventArgs.Empty) using the above, except without the extra method call).
I have code that looks something like this:
if(condition1)
{
//do some stuff
if(condition2)
{
//do some other stuff
if(condition3)
{
//do some more stuff
if(condition4)
{
//you probably got the point by now...
}
}
}
And I would like to re-factor it to code that looks better and is easier to follow.
So far the best I got Is:
do{
if(!condition1){break;}
//do some stuff
if(!condition2){break;}
//do some other stuff
if(!condition3){break;}
//do some more stuff
if(!condition4){break;}
//you probably got the point by now...
}while(false);
My question is:
Is there another better way I am missing?
I don't think it is relevant, but I am using C#...
Possibly encapsulate the functionality you need for each boolean condition into a method and use the method instead of specifying condition1, condition2, condition3 etc.
private boolean isRed() {
//do some stuff
}
private boolean isBlue() {
//do some other stuff
}
private boolean isGreen() {
//do some more stuff
}
...
if(isRed() && isBlue() && isGreen()) {
//do some more stuff
}
Since you are using C#, the idea of #dseibert could be extended a little bit more and made flexible using delegates, in this case Func.
You could create a List that holds Func's and add as many functions with the signature bool function(void) as you want and then evaluate the result of all of them using LINQ.
Three example functions to play with:
private bool isRed()
{
System.Console.WriteLine("red");
return true;
}
private bool isBlue()
{
System.Console.WriteLine("blue");
return false;
}
private bool isGreen()
{
System.Console.WriteLine("green");
return true;
}
List holding Funcs, that is filled with the test functions and initialized result:
var actions = new List<Func<bool>>();
actions.Add(() => isRed());
actions.Add(() => isGreen());
actions.Add(() => isBlue());
var result = true; // initial value
Evaluate all functions at once:
actions.ForEach(a => result &= a());
System.Console.WriteLine(result);
Now the only thing that you need to do is create a new method and add it to the list.
The downside of this solutions is that every method is always called even if the result is already false, but the code within the ForEach extension method could be optimized.
I'm working on a simple irc chat bot (specifically for twitch.tv streams), and I'm using a List to keep a list of all the users in the channel. When someone leaves or joins, I add or remove them from the list. Then I have a thread that runs every minute that checks if the stream is online, and if it is, it hands out "currency" to all the people in my user list.
I'm sure you can already see where my problem is. If someone leaves or joins while my program is looping through the users in my list, then I get a Collection Modified exception. Currently, as a workaround, I just make a temp list and copy the real list into it, then loop through the temp list instead, but I was just curious if there was a "better" way to do it?
Quick psuedocode:
private List<string> users = new List<string>();
private void IrcInitialize(){
//connect to irc stuff
//blah
//blah
//blah
Thread workThread = new Thread(new ThreadStart(doWork());
workThread.Start();
}
private void ircListener(){
parseIRCMessage(StreamReader.ReadLine());
}
private void parseIRCMessage(msg){
if (msgType == "JOIN"){
users.Add(user);
}
else if (msgType == "PART"){
users.Remove(user);
}
}
private void doWork(){
while (true) {
if (streamOnline() && handOutTime()){
handOutCurrency();
}
Thread.Sleep(60000);
}
}
private void handOutCurrency(){
List<string> temp = users; //This is what I'm currently doing
foreach (String user in temp) {
database.AddCurrency(user, 1);
}
}
Any other suggestions?
I suggest using a ConcurrentBag<string> for the users.
This allows multi-threaded access to the users even while it is being enumerated.
The big plus is that you do not have to worry about locking.
There are two ways to solve this problem:
Using a lock to synchronize access between two threads, or
Doing all access from a single thread.
The first way is simple: add lock(users) {...} block around the code that reads or modifies the users list.
The second way is slightly more involved: define two concurrent queues, toAdd and toRemove in your class. Instead of adding or removing users directly from the users list, add them to the toAdd and toRemove queues. When the sleeping thread wakes up, it should first empty both queues, performing the modifications as necessary. Only then it should hand out the currency.
ConcurrentQueue<string> toAdd = new ConcurrentQueue<string>();
ConcurrentQueue<string> toRemove = new ConcurrentQueue<string>();
private void parseIRCMessage(msg){
if (msgType == "JOIN"){
toAdd.Enqueue(user);
}
else if (msgType == "PART"){
toRemove.Enqueue(user);
}
}
private void doWork(){
while (true) {
string user;
while (toAdd.TryDequeue(out user)) {
users.Add(user);
}
while (toRemove.TryDequeue(out user)) {
users.Remove(user);
}
if (streamOnline() && handOutTime()){
handOutCurrency();
}
Thread.Sleep(60000);
}
}
The suggestions from dasblinkenlight's answer are good. Another option is to do something similar to what you suggested: work with a immutable copy of the list. Except with normal List, you would need to make sure that it's not changed while you're copying it (and you would actually need to copy the list, not just a reference to it, like your code suggested).
A better version of this approach would be to use ImmutableList from the immutable collections library. With that, each modification creates a new collection (but sharing most parts with the previous version to improve efficiency). This way, you could have one thread that modifies the list (actually, creates new lists based on the old one) and you could also read the list from another thread at the same time. This will work, because new changes won't be reflected in an old copy of the list.
With that, your code would look something like this:
private ImmutableList<string> users = ImmutableList<string>.Empty;
private void ParseIRCMessage(string msg)
{
if (msgType == "JOIN")
{
users = users.Add(user);
}
else if (msgType == "PART")
{
users = users.Remove(user);
}
}
private void HandOutCurrency()
{
foreach (String user in users)
{
database.AddCurrency(user, 1);
}
}
You need to lock on the list during all reads, writes, and iterations of the list.
private void parseIRCMessage(msg){
lock(users)
{
if (msgType == "JOIN"){
users.Add(user);
}
else if (msgType == "PART"){
users.Remove(user);
}
}
}
private void doWork(){
while (true) {
if (streamOnline() && handOutTime()){
handOutCurrency();
}
Thread.Sleep(60000);
}
}
private void handOutCurrency(){
lock(users)
{
foreach (String user in users) {
database.AddCurrency(user, 1);
}
}
}
etc...
In the following code, which is better? To call add page from within CardPanelDesigner_AddPage? Or use the Func TransactionFunction??
Basically I want to know if doing the inner func will create a "new function" every time :S I don't even know what I'm asking.
Is there an overhead to doing the inner function or should I use the addpage?
private object AddPage(IDesignerHost Host, object Sender)
{
return null;
}
private void CardPanelDesigner_AddPage(object sender, EventArgs e)
{
IDesignerHost DesignerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
if (DesignerHost != null)
{
Func<IDesignerHost, object, object> TransactionFunction = (Host, Param) =>
{
return null;
};
TransactionInfo("Add Page", DesignerHost, AddPage); //Add page? OR TransactionFunction? :S
}
}
Yes, TransactionFunction will create a new object each time CardPanelDesigner_AddPage is called. The performance overhead of this however will likely be negligible. You should do whatever reads best to you (and your team).