|
In my app, recently, I had to innovate some kind of daring concept.
Though, as it is perfectly syntactically correct, it did work fine.
This is not really a question here, more like a discussion here:
1. could I have made it more simple?
2. what do you think of it?
Enter async event!
Here is my code fragment that uses them
public event Func<Task> AlarmReceived
{
add { lock (this) eAlarmReceived += value; }
remove { lock (this) eAlarmReceived -= value; }
}
Func<Task> eAlarmReceived;
internal async Task OnAlarm()
{
if (eAlarmReceived == null)
return;
var eTasks = eAlarmReceived.GetInvocationList().Cast<Func<Task>>().ToList();
foreach (var t in eTasks)
await t();
}
modified 18-Jul-16 21:14pm.
|
|
|
|
|
It's an interesting concept.
What do you get when you cross a joke with a rhetorical question?
The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism.
Do questions with multiple question marks annoy you???
|
|
|
|
|
Thanks!
I was kind of not quite surprised but almost that it worked!
|
|
|
|
|
eAlarmReceived += value;
You can treat Func<Task> as a multicast delegate? I had no idea.
I've been playing around with this, and I'm not sure of the usage:
static void Main(string[] args)
{
new Program();
Console.ReadLine();
}
public Program()
{
DoIt();
}
public async void DoIt()
{
AlarmReceived += () => new Task(() => Console.WriteLine("A"));
AlarmReceived += () => new Task(() => Console.WriteLine("B"));
await OnAlarm();
}
That compiles but "A" and "B" never print -- what's a simple example of adding tasks to AlarmReceived?
[edit]
Never mind, I see what I was doing wrong. This works:
AlarmReceived += () => Task.Run(() => Console.WriteLine("A"));
AlarmReceived += () => Task.Run(() => Console.WriteLine("B"));
Now on to your question...
Marc
|
|
|
|
|
Glad you learned something Marc!
|
|
|
|
|
If this:
AlarmReceived += () => Task.Run(() => Console.WriteLine("A"));
is the correct syntax, then this:
AlarmReceived -= () => Task.Run(() => Console.WriteLine("A"));
doesn't unwire the delegate because it's a new instance. This "simpler" case (the way I might have tried it, because I didn't know about the multicast thingy) also doesn't unwire the alarms:
static void Main(string[] args)
{
new Program();
Console.ReadLine();
}
public Program()
{
DoIt2();
Console.WriteLine("Waiting for alarms to process...");
}
List<Action> alarmActions = new List<Action>();
public void AddAlarm(Action act)
{
alarmActions.Add(act);
}
public void RemoveAlarm(Action act)
{
alarmActions.Remove(act);
}
public async void DoIt2()
{
Console.WriteLine("Adding alarms");
AddAlarm(() => Alarm1());
AddAlarm(() => Alarm2());
await Task.Run(() => ProcessAlarms());
Console.WriteLine("Removing alarms");
RemoveAlarm(() => Alarm1());
RemoveAlarm(() => Alarm2());
await Task.Run(() => ProcessAlarms());
}
public void ProcessAlarms()
{
alarmActions.ForEach(a => a());
}
public void Alarm1()
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine("Alarm 1");
}
public void Alarm2()
{
Console.WriteLine("Alarm 2");
}
The only way to remove them is to instantiate the Action so the action isn't an anonymous method.
Action a = () => Alarm1();
Action b = () => Alarm2();
Console.WriteLine("Adding alarms");
AddAlarm(a);
AddAlarm(b);
await Task.Run(() => ProcessAlarms());
Console.WriteLine("Removing alarms");
RemoveAlarm(a);
RemoveAlarm(b);
await Task.Run(() => ProcessAlarms());
That approach is risky because, as the previous example showed, you could certainly wire up the alarm as an anonymous method, and the unwary programmer might think you can unwire it that way too, but you can't.
In your case, because AlarmReceived is an event of Task, I don't see how you can get away from an anonymous method:
Task a = Task.Run(() =>
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine("A");
}));
AlarmReceived += () => a;
The funny thing is, this ACTS like the event has been unwired because the task has been run!
Given:
public async void DoIt()
{
Task a = Task.Run(() =>
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine("A");
});
<pre>
Task b = Task.Run(() => Console.WriteLine("B"));
AlarmReceived += () => a;
AlarmReceived += () => b;
Console.WriteLine("Processing alarms");
await OnAlarm();
Console.WriteLine("Unwire");
AlarmReceived -= () => a;
AlarmReceived -= () => b;
await OnAlarm();
}
internal async Task OnAlarm()
{
if (eAlarmReceived == null)
{
Console.WriteLine("eAlarmReceived is null!");
return;
}
var eTasks = eAlarmReceived.GetInvocationList().Cast<Func<Task>>().ToList();
if (eTasks.Count == 0)
{
Console.WriteLine("Nothing to do!");
}
else
{
Console.WriteLine("Tasks = " + eTasks.Count);
foreach (var t in eTasks)
await t();
}
}</pre>
The output is:
Processing alarms
B
Tasks = 2
Waiting for alarms to process...
A
Unwire
Tasks = 2
But again, the use of the anonymous method for AlarmReceived means you can't unwire it.
Am I doing something different in the use case than you are?
Marc
|
|
|
|
|
Marc Clifton wrote: But again, the use of the anonymous method for AlarmReceived means you can't unwire it.
The same problem applies to regular events as well.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
|
I guess it mean aDelegate - aDelegate does something different that an Equal() comparison of its invocation list against the argument!
While it does something different. I am not sure what it is...
|
|
|
|
|
Stranger and stranger:
If I replace my original Source property implementation:
public AlarmSource Source
{
get { return source; }
set
{
Func<Task> handler = () => Task.Run(() => Console.WriteLine(Name));
if (source != null)
source.AlarmReceived -= handler;
source = value;
if (source != null)
source.AlarmReceived += handler;
}
}
AlarmSource source;
With this one
public AlarmSource Source
{
get { return source; }
set
{
if (source != null)
source.AlarmReceived -= () => Task.Run(() => Console.WriteLine(Name));
source = value;
if (source != null)
source.AlarmReceived += () => Task.Run(() => Console.WriteLine(Name));
}
}
AlarmSource source;
I do have the same bug as you have (i.e. the event handler is not removed).
This is relatively strange and I don't quite know what is happening...
But it is now narrowed down to a pretty strange syntax issue...
|
|
|
|
|
It is important to notice that you cannot easily unsubscribe from an event if you used an anonymous function to subscribe to it. To unsubscribe in this scenario, it is necessary to go back to the code where you subscribe to the event, store the anonymous method in a delegate variable, and then add the delegate to the event. In general, we recommend that you do not use anonymous functions to subscribe to events if you will have to unsubscribe from the event at some later point in your code.
I suspect your first sample works because you only have one anonymous method, which translates to a single hidden method:
Func<Task> handler = HiddenAnonymousMethod1;
if (source != null)
source.AlarmReceived -= handler;
source = value;
if (source != null)
source.AlarmReceived += handler;
In the second example, even though both anonymous methods are the same, they are probably translated to two different hidden methods:
if (source != null)
source.AlarmReceived -= HiddenAnonymousMethod1;
source = value;
if (source != null)
source.AlarmReceived += HiddenAnonymousMethod2;
You'd need to check the IL to verify that this is the case.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks Richard! That is a solid explanation here!
I might check it out!
|
|
|
|
|
If you have multiple handlers subscribed to the event, they will run sequentially. I'd be inclined to let them run in parallel.
You should probably also add a lock around the code that retrieves the list of handlers, to match the lock in the add / remove accessors.
private static readonly Task CompletedTask = Task.FromResult(true);
private IEnumerable<Func<Task>> GetAlarmInvocationList()
{
lock (this)
{
Func<Task> handler = eAlarmReceived;
if (handler == null) return null;
return handler.GetInvocationList().Cast<Func<Task>>().ToList();
}
}
internal Task OnAlarm()
{
var eTasks = GetAlarmInvocationList();
if (eTasks == null) return CompletedTask;
var tasks = eTasks.Select(fn => fn());
return Task.WhenAll(tasks);
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
well.. it depends.. I wondered about running it in parallel too.
But I went against it.
In my case this is mobile phone code stuff. It mostly run sequentially. It just happen that some method are async....
As to the firing without lock... In fact you are right, I stupidly left a bug I knew about...
Juts because lock bothered me and the solution I had iin mind bother me too...
The solution I had in mind:
var eTasks = handler?.GetInvocationList()?.Cast<Func<Task>>()?.ToList();
if (eTask == null)
return;
foreach (var t in eTask)
await t();
The null invocation parameter.... might take care of multithread access issues, I think....
|
|
|
|
|
For example the code below
Pipeline pipeline = runspacee.CreatePipeline();
pipeline.Commands.Add(command1);
pipeline.Commands.Add(command2);
var exResults = pipeline.Invoke();
powershell.AddCommand("set-adserversettings")
.AddParameter("viewentireforest", true)
.AddParameter(";");
powershell.AddCommand("set-userphoto")
.AddParameter("Identity", tbxName.Text)
.AddParameter("picturedata", displayedImage)
.AddParameter("DomainController", "12-34-56-01.XXX.XXX.XXXX.XXX")
.AddParameter("confirm ", false)
.AddParameter(";");
|
|
|
|
|
... and your question is?
|
|
|
|
|
How can I run the code above in C#?
I can run single powershell commands, but nothing requiring multiple commands such as the example code I posted.
For example, I could run set-userphoto, but if I have to import a module or set-adserversettings, I cannot get that to work?
|
|
|
|
|
What is contained in command1 and command2 in your code snippet? And what results or errors do you see?
|
|
|
|
|
I should have removed the command1 and command2, those were just additional ways of me trying the same thing. Sorry about that.
Error message is
Quote: - The term 'Import-Module' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. - System.Management.Automation - at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection`1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings) at System.Management.Automation.PowerShell.Invoke(IEnumerable input) at System.Management.Automation.RemotePipeline.Invoke(IEnumerable input) at System.Management.Automation.Runspaces.Pipeline.Invoke() at exchangePictureUpdater.exchangePictureUpdater.btnAddReplace_Click(Object sender, EventArgs e) - Void CoreInvoke[TOutput](System.Collections.IEnumerable, System.Management.Automation.PSDataCollection`1[TOutput], System.Management.Automation.PSInvocationSettings) |
Command command1 = new Command("set-adserversettings");
CommandParameter parameter1 = new CommandParameter("viewentireforest", true);
command1.Parameters.Add(parameter1);
Command command2 = new Command("set-userphoto");
CommandParameter parameter2a = new CommandParameter("identity", tbxName.Text);
CommandParameter parameter2b = new CommandParameter("picturedata", displayedImage);
CommandParameter parameter2c = new CommandParameter("domaincontroller", "adfadfadf.com");
CommandParameter parameter2d = new CommandParameter("confirm", false);
command2.Parameters.Add(parameter2a);
command2.Parameters.Add(parameter2b);
command2.Parameters.Add(parameter2c);
command2.Parameters.Add(parameter2d);
Pipeline pipeline = runspacee.CreatePipeline();
pipeline.Commands.Add(command1);
pipeline.Commands.Add(command2);
|
|
|
|
|
|
results = pipeline.Invoke()
I need a working example of how to do this, and after that I can modify it to my own needs
|
|
|
|
|
Here is what I ended up doing, this allows me to create a script in a string with multiple commands, it processes 1 command at a time and then creates a runspace in c# and runs all of the powershell commands
string scriptText = @"$pw = convertto-securestring -AsPlainText -Force -String '<password>'; $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist '<domain>\<username>', $pw; $session = new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri '<server url>/powershell' -credential $cred; import-pssession $session; Set-ExecutionPolicy bypass -confirm:$false -force; $pic = ([System.IO.File]::ReadAllBytes('" + <picture file name> + "')); set-userphoto -identity <username> -picturedata $pic -domaincontroller '<dc fqdn>' -confirm:$false;";
runExchangeShellScript(scriptText);
private string runExchangeShellScript(string scriptText)
{
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);
RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runspace);
runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
Collection<PSObject> results = null;
try
{
results = pipeline.Invoke();
}
catch (Exception ex)
{
MessageBox.Show(ex.InnerException + " - " + ex.Message + " - " + ex.Source + " - " + ex.StackTrace + " - " + ex.TargetSite + " - " + ex.Data);
return "";
}
runspace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
|
|
|
|
|
Suppose you have two forms: frmMain and frmPopup, on frmMain has 1 button (the button) click open frmPopup, on frmPopup many (button), you click on the button any frmPopup button will transmit data by the delegate of copper frmMain frmPopup before closing time announced new open yes / no of MessageBox.Show. When your done click the close button again poup frmPopup then MessageBox.Show on frmPopup, frmPopup refused to play, until the click buttons yes/no of MessageBox.Show, click the button here as yes / no, then frmPopup and MessageBox. Show it to close. I want to play a new fat frmPopup MessageBox.Show done. Their code has the following structure:
[code]
//Declare frmMain
public partial class frmMain : Form
{
private void getData(data)
{
if (conditions) Updata();
}
public frmMain()
{
InitializeComponent();
}
private void cmdfrmPopup_Click(object sender, EventArgs e)
{
frmPopup frm = new frmPopup(data);
frm.Data = getData;
frm.ShowDialog();
}
private void Updata()
{
DialogResult dlgRes;
string sAskUser = "Are you sure delete ?" ...
dlgRes = MessageBox.Show(sAskUser, "warning..", MessageBoxButtons.YesNo, Question);
if (dlgRes == DialogResult.OK)
{
}
}
}
//Khai báo frmPoup
public partial class frmPopup : Form
{
public frmPopup(nhandulieuden)
{
InitializeComponent();
}
private void cmdButton1_Click(object sender, EventArgs e)
{
Process();
}
private void cmdButton2_Click(object sender, EventArgs e)
{
Process();
}
private void cmdButton3_Click(object sender, EventArgs e)
{
Process();
}
private void cmdButton4_Click(object sender, EventArgs e)
{
Process();
}
private void Xuly()
{
this.Close();
transmissionOffrmMain(data);
}
private void cmdExit_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
[/code]
through available tracks your household help this place.
|
|
|
|
|
If your message does not appear immediately, do not repost it again, and again, and again...
Your original post was sent to moderation by the automated spam detector, and it took a human (or in this case me) to decide to approve or reject it for publication. And to avoid giving you a severe kicking as a spammer, I had to let all of them through and then go clean up after you later. Which is a waste of my time!
If it doesn't post immediately, give it a few moments - we work as fast as we can, but we are all volunteers with other demands on our time.
I've deleted the three spare version of this...
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
hello people of code project i have the following code.
private String header;
private Dictionary<String, String> tokens;
public DevExpress.XtraEditors.TextEdit txtDisplayName;
public DevExpress.XtraEditors.ListBoxControl lstwep;
public DevExpress.XtraEditors.SimpleButton elfenliedbutton;
public DevExpress.XtraEditors.TextEdit txtmaxammo;
public LauncherForm elfform;
private String file;
public Parser(String file, DevExpress.XtraEditors.ListBoxControl lstelfen, LauncherForm elfform1)
{
elfform = elfform1;
lstwep = lstelfen;
this.file = file;
String plainText;
using (StreamReader sr = new StreamReader(file))
{
plainText = sr.ReadToEnd();
}
String[] tokens = plainText.Split('\\');
this.tokens = new Dictionary<string, string>(tokens.Length + 10);
header = tokens[0];
for (int i = 1; i < tokens.Length; i += 2)
{
String key = tokens[i];
String val = (i + 1 <= tokens.Length) ? tokens[i + 1] : "";
this.tokens.Add(key, val);
}
}
public String Search(String name)
{
foreach (KeyValuePair<String, String> pair in tokens)
{
if (pair.Key == name)
return pair.Value;
}
return null;
}
public void Set(String key, String val)
{
tokens[key] = val;
}
public void Save(String file)
{
using (StreamWriter sw = new StreamWriter(File.OpenWrite(file)))
{
sw.Write(header);
foreach (KeyValuePair<String, String> pair in tokens)
{
sw.Write("\\" + pair.Key + "\\" + pair.Value);
}
}
}
public void Save()
{
this.Save(file);
}
}
what i want to do is generate a list box with all weapon files in a mod and when one is selected it will execute the parse code
here is a little muck up i made in gui to explain better what i mean
http://i.imgur.com/khoG06h.png[^]
as you can see form below code i can get the file to parse but i want to load all the weapon file names form directory and list them all in the listbox then when i select a name it will load the weapon file into selected boxes
but im not sure how to do this i managed to get it to work with push of a button but i cant seem to get it to list weapon files into the listbox and then on a select it will run the code to load the selected weapon file and then display its values to text box then save it out. and here is the one example weapon file so its easy to understand what im trying to do.
MEGA[^]
so form example weapon file for example displayName/weaponname/ thats how they are layied out
thank you in advance elfenliedtopfan5
|
|
|
|