Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
User0015
Nov 24, 2007

Please don't talk about your sexuality unless it serves the ~narrative~!
In that example, I cannot modify Foo. I need to use it's public event to listen for completion.

Adbot
ADBOT LOVES YOU

LongSack
Jan 17, 2003


Luckily for me, there are no other devs :confuoot: I’m not a developer, I’m a firewall engineer writing tools that help me streamline my daily grind.

I implement IEquatable<T> when an object has a unique identifier of some sort, be it a UUID/Guid or identity key. I implement IComparable<T> when a class has an obvious sort field, like Name, or Description.

The only time I’ve done anything “clever” (in the pejorative sense) is my Time class, which freely converts to/from double where, for instance, 12:30 pm can be represented as 12.5

I understand what you guys are saying, and I don’t discount it, but as yet (knock on wood) I’ve yet to suffer any adverse effects from doing it this way, and (IMO) the code reads cleaner.

ThePeavstenator
Dec 18, 2012

:burger::burger::burger::burger::burger:

Establish the Buns

:burger::burger::burger::burger::burger:

User0015 posted:

Phone posting here, but what happens to events when a using statement completes? For example

Using(var foo = new Foo()) {
...
foo.workCompleteZugZug += SomeHandler(...);
await foo.DoWork();
}

Once that completes, does that clean up properly on dispose? I'm wondering if that leaves behind a reference somewhere.

foo holds a reference to the SomeHandler action delegate, not the other way around, so foo will get GCd

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

LongSack posted:

Luckily for me, there are no other devs :confuoot: I’m not a developer, I’m a firewall engineer writing tools that help me streamline my daily grind.

I implement IEquatable<T> when an object has a unique identifier of some sort, be it a UUID/Guid or identity key. I implement IComparable<T> when a class has an obvious sort field, like Name, or Description.

The only time I’ve done anything “clever” (in the pejorative sense) is my Time class, which freely converts to/from double where, for instance, 12:30 pm can be represented as 12.5

I understand what you guys are saying, and I don’t discount it, but as yet (knock on wood) I’ve yet to suffer any adverse effects from doing it this way, and (IMO) the code reads cleaner.

Yo try working with other developers and see how that works for you. I'd loving never overload an operator unless a gun were pointed to my head in a commercial environment.

ThePeavstenator
Dec 18, 2012

:burger::burger::burger::burger::burger:

Establish the Buns

:burger::burger::burger::burger::burger:

LongSack posted:

The only time I’ve done anything “clever” (in the pejorative sense) is my Time class, which freely converts to/from double where, for instance, 12:30 pm can be represented as 12.5

even ignoring the comparison thing, you will heavily regret writing any time implementation yourself the second you have to deal with anything other than static time stamps

if you have any logic surrounding time don't even use the .NET DateTime types, just use NodaTime

LongSack posted:

and (IMO) the code reads cleaner.

less text =/= cleaner code

ThePeavstenator
Dec 18, 2012

:burger::burger::burger::burger::burger:

Establish the Buns

:burger::burger::burger::burger::burger:
if all of your code is basically just scripts for your own productivity and you know all the implementation details in your head than it's probably fine, but don't mistake abstraction for making things cleaner

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

ThePeavstenator posted:

...you will heavily regret writing any time implementation yourself...
if you have any logic surrounding time don't even use the .NET DateTime types, just use NodaTime


Yes, this.

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Bruegels Fuckbooks posted:

Yo try working with other developers and see how that works for you. I'd loving never overload an operator unless a gun were pointed to my head in a commercial environment.

My rule of thumb for operator overloading: can this class be described as "a wrapper around a single primitive value"? If yes, then overload operators so that they behave the same as the primitive. Otherwise, don't overload them.

Eg. let's say you have a Weight class that wraps around the raw decimal value and adds unit-of-measure conversion, tare, precision, maybe timestamps. Then it's intuitive what Weight1 > Weight2 means. But now let's say you have a ProductWeight class that wraps the combination of the product being weighted and the weight itself: at this point someone might expect AppleWeight1 > OrangeWeight2 to ignore the product and just compare weights, while others might expect it to only compare if the product is the same and otherwise throw ArgumentException, so it's better not to provide operators.

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

NihilCredo posted:

My rule of thumb for operator overloading: can this class be described as "a wrapper around a single primitive value"? If yes, then overload operators so that they behave the same as the primitive. Otherwise, don't overload them.

Eg. let's say you have a Weight class that wraps around the raw decimal value and adds unit-of-measure conversion, tare, precision, maybe timestamps. Then it's intuitive what Weight1 > Weight2 means. But now let's say you have a ProductWeight class that wraps the combination of the product being weighted and the weight itself: at this point someone might expect AppleWeight1 > OrangeWeight2 to ignore the product and just compare weights, while others might expect it to only compare if the product is the same and otherwise throw ArgumentException, so it's better not to provide operators.

At least in my experience, that kind of thinking will teach you that your coworkers either a) don't understand the commutative property, order of operations, or where the code for the operator is, or b) will point out that you've screwed up something in your implementation that relies on these intuitions. Method calls are relatively idiot-proof.

raminasi
Jan 25, 2005

a last drink with no ice

User0015 posted:

Phone posting here, but what happens to events when a using statement completes? For example

Using(var foo = new Foo()) {
...
foo.workCompleteZugZug += SomeHandler(...);
await foo.DoWork();
}

Once that completes, does that clean up properly on dispose? I'm wondering if that leaves behind a reference somewhere.

There being an event is orthogonal to the using statement. All using does is ensure that Dispose is called at the end of the block. If your Dispose interacts with your event, then it will matter; otherwise, it won't.

The other part of your question ("How do events relate to object lifetimes?") is a good one. Here, foo will maintain a reference to SomeHandler (that's how it knows what to call!), so SomeHandler won't be GCed until foo is.

fuf
Sep 12, 2004

haha
Maybe wrong thread but does anyone have any advice on finding a host for a few very small Umbraco sites?

I'm building a few small projects just to pad out my portfolio and hopefully get a job, and I want to host them somewhere as cheaply as possible (but still perform relatively well on the off chance they start generating traffic).

Azure and Umbraco cloud are too expensive (although it's hard to tell with Azure, it's like everything is either free or hugely expensive).

I'm being tempted by crappy shared hosting plans that are incredibly cheap and promising the world, but I imagine performance will be terrible...

Am I asking for trouble if I try and manage my own VPS? I've managed a few linux servers but never windows...

Careful Drums
Oct 30, 2007

by FactsAreUseless

fuf posted:

Maybe wrong thread but does anyone have any advice on finding a host for a few very small Umbraco sites?

I'm building a few small projects just to pad out my portfolio and hopefully get a job, and I want to host them somewhere as cheaply as possible (but still perform relatively well on the off chance they start generating traffic).

Azure and Umbraco cloud are too expensive (although it's hard to tell with Azure, it's like everything is either free or hugely expensive).

I'm being tempted by crappy shared hosting plans that are incredibly cheap and promising the world, but I imagine performance will be terrible...

Am I asking for trouble if I try and manage my own VPS? I've managed a few linux servers but never windows...

One of my freelance clients uses this place to host his small .NET apps: https://www.smarterasp.net/ I hate working with them but it's because I'm spoiled by Azure. My client loves them.

But if you have access to .NET Dev Essentials, or BizSpark, or whatever it's called, you get $150/mo in free Azure credits, and that goes a long way for small non-enterprise hosting. I use that for my personal stuff.

fuf
Sep 12, 2004

haha

Careful Drums posted:

But if you have access to .NET Dev Essentials, or BizSpark, or whatever it's called, you get $150/mo in free Azure credits, and that goes a long way for small non-enterprise hosting. I use that for my personal stuff.

Hmm thanks for the tip. I don't see the 150/mo thing, just an initial free credit of 150 and then "free services" for 12 months. But again it's kind of unclear.

I think I'll give Azure a go. Even if I end up having to move somewhere else it will still be a learning experience.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



https://appharbor.com/pricing has a free tier and their actually paid plans are pretty simple to understand.

epswing
Nov 4, 2003

Soiled Meat
I have an async/await question.

A long time ago, back in the WebClient, pre-async/await days, the following RetryAction class was created:

C# code:
public class RetryAction
{
    private int retryCount;
    private TimeSpan retryDelay;
    private Action action;

    public RetryAction(int retryCount, TimeSpan retryDelay, Action action)
    {
        this.retryCount = retryCount;
        this.retryDelay = retryDelay;
        this.action = action;
    }

    public Task Start()
    {
        Debug.Assert(retryCount > 0);

        return Task.Factory.StartNew(() =>
        {
            while (true)
            {
                try
                {
                    action();
                    break;
                }
                catch
                {
                    retryCount--;

                    if (retryCount > 0)
                        Thread.Sleep(retryDelay);
                    else
                        throw;
                }
            }
        });
    }
}
Just a simple class to fire-and-forget things like e.g. POSTing to a 3rd party. For example, to retry 3 times, with a delay of 5 seconds after each retry, might look something like this. The calls to Console.WriteLine would actually be some logging mechanism

C# code:
protected override void btn_Click(object sender, RoutedEventArgs e)
{
    Send();
}

private void Send()
{
    new RetryAction(3, TimeSpan.FromSeconds(5), () =>
    {
        using (var client = new WebClient())
        {
            try
            {
                Console.WriteLine($"{DateTime.Now} sending");
                client.UploadData(new Uri("http://some-unresponsive-url.com"), new byte[0]);
            }
            catch (Exception e)
            {
                Console.WriteLine($"{DateTime.Now} error: {e.Message}");
                throw;
            }
        }
    }).Start();
}
In the case of failure, the log would show that we tried, and failed, 3 times:
pre:
3/7/2019 12:44:15 PM sending
3/7/2019 12:44:15 PM error: The remote name could not be resolved: 'some-unresponsive-url.com'
3/7/2019 12:44:20 PM sending
3/7/2019 12:44:20 PM error: The remote name could not be resolved: 'some-unresponsive-url.com'
3/7/2019 12:44:25 PM sending
3/7/2019 12:44:25 PM error: The remote name could not be resolved: 'some-unresponsive-url.com'
This implementation and usage of RetryAction has obvious some problems. For example, after all the retries, there's no way to catch the final throw. But we've mostly just used it as a fire-and-forget, and there wasn't actually any action we wanted to take after failing anyways.

Fast forward to the HttpClient days, where everything is awaitable and methods are postfixed with "Async". Here's what the usage might look like:

C# code:
protected async void btn_Click(object sender, RoutedEventArgs e)
{
    await Send();
}

private async Task Send()
{
    await new RetryAction(3, TimeSpan.FromSeconds(5), async () =>
    {
        using (var client = new HttpClient())
        {
            try
            {
                Console.WriteLine($"{DateTime.Now} sending");
                await client.PostAsync(new Uri("http://some-unresponsive-url.com"), null);
            }
            catch (Exception e)
            {
                Console.WriteLine($"{DateTime.Now} error: {e.Message}");
                throw; // user-unhandled exception here
            }
        }
    }).Start();
}
Without yet modifying RetryAction, above marked throw yields a user-unhandled exception.

Here's what we'd see in the log:

pre:
3/7/2019 12:51:50 PM sending
3/7/2019 12:51:50 PM error: An error occurred while sending the request.
OK, now you're all caught up. I'm looking at creating a RetryActionAsync class, that has the same or similar functionality. I want to specify how many times to retry, how long to wait between retries, and pass an anonymous action to perform.

Is there something in .NET that accomplishes this already?
How would I modify RetryAction to be async/await friendly?
Could it be done in such a way that I could indeed get back the exception after the last retry?

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


epalm posted:

I have an async/await question.

A long time ago, back in the WebClient, pre-async/await days, the following RetryAction class was created:

C# code:
public class RetryAction
{
    private int retryCount;
    private TimeSpan retryDelay;
    private Action action;

    public RetryAction(int retryCount, TimeSpan retryDelay, Action action)
    {
        this.retryCount = retryCount;
        this.retryDelay = retryDelay;
        this.action = action;
    }

    public Task Start()
    {
        Debug.Assert(retryCount > 0);

        return Task.Factory.StartNew(() =>
        {
            while (true)
            {
                try
                {
                    action();
                    break;
                }
                catch
                {
                    retryCount--;

                    if (retryCount > 0)
                        Thread.Sleep(retryDelay);
                    else
                        throw;
                }
            }
        });
    }
}
Just a simple class to fire-and-forget things like e.g. POSTing to a 3rd party. For example, to retry 3 times, with a delay of 5 seconds after each retry, might look something like this. The calls to Console.WriteLine would actually be some logging mechanism

C# code:
protected override void btn_Click(object sender, RoutedEventArgs e)
{
    Send();
}

private void Send()
{
    new RetryAction(3, TimeSpan.FromSeconds(5), () =>
    {
        using (var client = new WebClient())
        {
            try
            {
                Console.WriteLine($"{DateTime.Now} sending");
                client.UploadData(new Uri("http://some-unresponsive-url.com"), new byte[0]);
            }
            catch (Exception e)
            {
                Console.WriteLine($"{DateTime.Now} error: {e.Message}");
                throw;
            }
        }
    }).Start();
}
In the case of failure, the log would show that we tried, and failed, 3 times:
pre:
3/7/2019 12:44:15 PM sending
3/7/2019 12:44:15 PM error: The remote name could not be resolved: 'some-unresponsive-url.com'
3/7/2019 12:44:20 PM sending
3/7/2019 12:44:20 PM error: The remote name could not be resolved: 'some-unresponsive-url.com'
3/7/2019 12:44:25 PM sending
3/7/2019 12:44:25 PM error: The remote name could not be resolved: 'some-unresponsive-url.com'
This implementation and usage of RetryAction has obvious some problems. For example, after all the retries, there's no way to catch the final throw. But we've mostly just used it as a fire-and-forget, and there wasn't actually any action we wanted to take after failing anyways.

Fast forward to the HttpClient days, where everything is awaitable and methods are postfixed with "Async". Here's what the usage might look like:

C# code:
protected async void btn_Click(object sender, RoutedEventArgs e)
{
    await Send();
}

private async Task Send()
{
    await new RetryAction(3, TimeSpan.FromSeconds(5), async () =>
    {
        using (var client = new HttpClient())
        {
            try
            {
                Console.WriteLine($"{DateTime.Now} sending");
                await client.PostAsync(new Uri("http://some-unresponsive-url.com"), null);
            }
            catch (Exception e)
            {
                Console.WriteLine($"{DateTime.Now} error: {e.Message}");
                throw; // user-unhandled exception here
            }
        }
    }).Start();
}
Without yet modifying RetryAction, above marked throw yields a user-unhandled exception.

Here's what we'd see in the log:

pre:
3/7/2019 12:51:50 PM sending
3/7/2019 12:51:50 PM error: An error occurred while sending the request.
OK, now you're all caught up. I'm looking at creating a RetryActionAsync class, that has the same or similar functionality. I want to specify how many times to retry, how long to wait between retries, and pass an anonymous action to perform.

Is there something in .NET that accomplishes this already?
How would I modify RetryAction to be async/await friendly?
Could it be done in such a way that I could indeed get back the exception after the last retry?
Are you able to use third party packages? Because Polly is great for this.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug
You can't use Actions, you have to use Func<Task>. This is from memory but I've used something similar to this before:

code:
public static async Task MakeAsyncCallWithRetryOnException(this Func<Task> activity, int retryCount = 5, int retryDelayInSeconds = 5)
        {
            while (true)
            {
                try
                {
                    await activity().ConfigureAwait(false);
                }
                catch
                {
                    if (retryCount == 0)
                    {
                        throw;
                    }
                    retryCount--;
                    await Task.Delay(retryDelayInSeconds * 1000);
                }
            }
        }

Night Shade
Jan 13, 2013

Old School

Nth Doctor posted:

Are you able to use third party packages? Because Polly is great for this.

Yes, Polly is amazing and you should definitely use it instead of rolling your own async retry and circuit breaker mechanisms.

Careful Drums
Oct 30, 2007

by FactsAreUseless
Using a well-established framework such as Polly is probably the best way to solve that problem.

But I'm curious. How would you go about writing that asynchronously? Without doing a bunch of homework, I don't know.

Scaramouche
Mar 26, 2001

SPACE FACE! SPACE FACE!

Is there a way to get timings on all events that occur on a pageload? I've got an ASPX page I'm diagnosing that has a 26s "waiting" time in Chrome inspector before any payload reaches the browser. This isn't surprising, because it has sub-tabs on it that each load up with like, Address Info, Order History, etc etc. The thing is, so many things are loading I can't really step through all of them see. What I was hoping is I could just turn something on during the debug, VS records how long each thing takes, then I could stop it, and examine what the longest running events are.

The events already get listed in the Diagnostic Tools > Events section, but there's no timings attached to them, just "Thing 1 happened\nThing 2 happened". I think what I'd like is the Delta between Thing 1 and Thing 2. This happens when you're F10ing through the code with that little x ms popup, but I was hoping to have it harvest/record automatically.

Apologies if this is a basic question, I'm really more of a server guy, and really not much of a VS guy. If you're wondering why such a guy is even looking at this, it's a little self improvement project I've taken on to track down some of these more involved complaints and get them more codified before handing them off to a real programmer.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Scaramouche posted:

Is there a way to get timings on all events that occur on a pageload? I've got an ASPX page I'm diagnosing that has a 26s "waiting" time in Chrome inspector before any payload reaches the browser. This isn't surprising, because it has sub-tabs on it that each load up with like, Address Info, Order History, etc etc. The thing is, so many things are loading I can't really step through all of them see. What I was hoping is I could just turn something on during the debug, VS records how long each thing takes, then I could stop it, and examine what the longest running events are.

The events already get listed in the Diagnostic Tools > Events section, but there's no timings attached to them, just "Thing 1 happened\nThing 2 happened". I think what I'd like is the Delta between Thing 1 and Thing 2. This happens when you're F10ing through the code with that little x ms popup, but I was hoping to have it harvest/record automatically.

Apologies if this is a basic question, I'm really more of a server guy, and really not much of a VS guy. If you're wondering why such a guy is even looking at this, it's a little self improvement project I've taken on to track down some of these more involved complaints and get them more codified before handing them off to a real programmer.

https://docs.microsoft.com/en-us/visualstudio/profiling/?view=vs-2017

Nth Doctor
Sep 7, 2010

Darkrai used Dream Eater!
It's super effective!


Careful Drums posted:

Using a well-established framework such as Polly is probably the best way to solve that problem.

But I'm curious. How would you go about writing that asynchronously? Without doing a bunch of homework, I don't know.

I'm not sure what you mean, but you can have a async execution on a retry policy:
https://github.com/App-vNext/Polly/wiki/Retry
https://github.com/App-vNext/Polly#asynchronous-support

When you run out of retries, the last exception is thrown out of your ExecuteAsync() call.

Here's something I threw together in LINQPad:

code:
using Polly;
using Polly.Retry;
using System.Threading.Tasks;
int count;
async Task Main()
{
  // This hoop-jumping is just me doing some convenience work so I don't need to do too much rebuilding between the first and second demonstrations.
  var builder = Policy
    .Handle<ArgumentException>()
    .Or<Exception>()
    // and so on as needed
    ;

  AsyncRetryPolicy retryPolicy = builder
    .RetryAsync(1, async (exception, retryCount, context) => await OnRetryAction(exception, retryCount, context));
  
  await DemonstratePolicy(retryPolicy);

  retryPolicy = builder
    .RetryAsync(2, async (exception, retryCount, context) => await OnRetryAction(exception, retryCount, context));

  await DemonstratePolicy(retryPolicy);

}

// Define other methods and classes here

// This is just so I don't need to create identical actions for each demonstration
async Task OnRetryAction(Exception exceptionThatWasCaught, int retryCount, Context context)
{
  // Do whatever handling of errors caught by retry here you want to do.
  Console.WriteLine($"Caught exception of type {exceptionThatWasCaught.GetType()}: \"{exceptionThatWasCaught.Message}\" on try {retryCount}.  Will retry.");
  await Task.Delay(0);
}

// Execute my flaky-rear end method and try to print the results.
async Task DemonstratePolicy(AsyncPolicy retryPolicy)
{
  string arg2 = "jklsemicolon";
  count = 0;
  
  try
  {
    var result = await retryPolicy.ExecuteAsync<string>(
      async (context) => { return await DoAThing((string)context["arg1"], arg2); },
      new Dictionary<string, object>{
        {"arg1","asdf"}
      }
    );

    Console.WriteLine($"Successfully got \"{result}\" on try number {count}");
  }
  catch (Exception e)
  {
    // The final time we get a failure, if we run out of retries, we end up here.
    Console.WriteLine($"Caught exception of type {e.GetType()}: \"{e.Message}\" after exhausting all of our retry attempts.  Will not retry anymore.");
  }
}

// Simple method that will error two times in different ways and then succeed.
async Task<string> DoAThing(string arg1, string arg2)
{
  count++;

  if(count == 1){
    throw new Exception("First failure");
  }
  else if(count == 2){
    throw new ArgumentException("Second failure");
  }
  await Task.Delay(0);
  return $"{arg1}-{arg2}";
}
Executing this gives this output:

quote:

Caught exception of type System.Exception: "First failure" on try 1. Will retry.
Caught exception of type System.ArgumentException: "Second failure" after exhausting all of our retry attempts. Will not retry anymore.
Caught exception of type System.Exception: "First failure" on try 1. Will retry.
Caught exception of type System.ArgumentException: "Second failure" on try 2. Will retry.
Successfully got "asdf-jklsemicolon" on try number 3

Scaramouche
Mar 26, 2001

SPACE FACE! SPACE FACE!


FFS it was there already, but the event profiler was default docked to right, the Time/Duration/Thread columns were invisible off to the right, and when it's docked it doesn't let you scroll the display.

raminasi
Jan 25, 2005

a last drink with no ice
I've got a weird loving WPF problem with a combobox..

On some user machines (but not all!) clicking the combobox to drop the menu down works fine, but then clicking on a menu item doesn't select it; it's like the click is ignored. You can do the selection fine using the arrow keys, and you can actually click and drag on the combobox like an old-style menu, but click, move pointer, click doesn't work. (You can even do weird poo poo like mouse down, drag menu open, highlight target selection, drag mouse off of menu, click to close menu without changing selection, click menu again, move pointer to item you highlighted before but didn't select, and then click, and that will work.) I've attached some event handlers to see what events are being fired, and it looks like PreviewMouseUp doesn't happen in the broken case, but it does in the working case. The WPF form is inside a WindowsFormsHost which is in turn somehow rendered by the 3d modeler hosting the plugin I'm writing for it, so there's plenty of potential for shenanigans, but I'm totally out of ideas for actually fixing this or even diagnosing it.

NoDamage
Dec 2, 2000

epalm posted:

OK, now you're all caught up. I'm looking at creating a RetryActionAsync class, that has the same or similar functionality. I want to specify how many times to retry, how long to wait between retries, and pass an anonymous action to perform.

Is there something in .NET that accomplishes this already?
How would I modify RetryAction to be async/await friendly?
Could it be done in such a way that I could indeed get back the exception after the last retry?
The problem is you're passing in an async void lambda as an argument that takes an Action and then invoking the action without awaiting it: https://devblogs.microsoft.com/pfxteam/potential-pitfalls-to-avoid-when-passing-around-async-lambdas/

You should generally avoid defining async void methods because their exception handling does not behave the way you expect: http://www.informit.com/articles/article.aspx?p=2832590&seqNum=2

And you should probably use Task.Run instead of Task.Factory.StartNew because the latter does not play well with async: https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/

I think you can fix your problem by 1) changing Action to Func<Task>, 2) awaiting the call to the action, and 3) replacing Task.Factory.StartNew with Task.Run. Or find a library that does this all for you because getting the details right can be tricky.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

NoDamage posted:

The problem is you're passing in an async void lambda as an argument that takes an Action and then invoking the action without awaiting it: https://devblogs.microsoft.com/pfxteam/potential-pitfalls-to-avoid-when-passing-around-async-lambdas/

You should generally avoid defining async void methods because their exception handling does not behave the way you expect: http://www.informit.com/articles/article.aspx?p=2832590&seqNum=2

And you should probably use Task.Run instead of Task.Factory.StartNew because the latter does not play well with async: https://devblogs.microsoft.com/pfxteam/task-run-vs-task-factory-startnew/

I think you can fix your problem by 1) changing Action to Func<Task>, 2) awaiting the call to the action, and 3) replacing Task.Factory.StartNew with Task.Run. Or find a library that does this all for you because getting the details right can be tricky.

There's no need to start a new task at all, the func returns an awaitable task.

NoDamage
Dec 2, 2000

New Yorp New Yorp posted:

There's no need to start a new task at all, the func returns an awaitable task.
Ah yes you're right, the outer Task.Factory.StartNew can be removed entirely.

death cob for cutie
Dec 30, 2006

dwarves won't delve no more
too much splatting down on Zot:4
I'm a bit of a newbie C# programmer (usually I code in Python) and I'm running into some incredible difficulty. I can't tell if this is me loving up something simple, or if the error is miraculously someone else's fault.

I'm using FileHelpers to transform lines in a .csv representing airports into simple objects that have properties correlating with each of the columns in the .csv. This is not a problem. The problem comes when I go to validate what's stored in each property before I suck the object into my database - I cannot seem to compare strings Here's a sample line from the .csv (along with the header at the top of the .csv):

pre:
"id","ident","type","name","latitude_deg","longitude_deg","elevation_ft","continent","iso_country","iso_region","municipality","scheduled_service","gps_code","iata_code","local_code","home_link","wikipedia_link","keywords"
3754,"KORD","large_airport","Chicago O'Hare International Airport",41.9786,-87.9048,672,"NA","US","US-IL","Chicago","yes","KORD","ORD","ORD","https://www.flychicago.com/ohare/home/pages/default.aspx","http://en.wikipedia.org/wiki/O'Hare_International_Airport","CHI, Orchard Place"
I have a little test method to try and figure out what's loving up. "testrecords" is a series of records I wrote for unit tests; the object at index 6 contains the line I posted above. The same behavior is exhibited no matter what test case I use through. I'll give you the code and its output in little chunks.

input:
pre:
Console.WriteLine(testrecords[6].ident);
Console.WriteLine(testrecords[6].ident.GetType());
Console.WriteLine("KORD".GetType());
output:
pre:
"KORD"
System.String
System.String
This is just me making sure that the object has the right ident and that it's a String - I was thinking it was producing some custom datatype from FileHelpers that would print a string to console, or had a string representation available, but wasn't actually a string.

input:
pre:
Console.WriteLine(testrecords[6].ident == "KORD");
Console.WriteLine(testrecords[6].ident.Equals("KORD"));
Console.WriteLine(String.Equals(testrecords[6].ident, "KORD"));
Console.WriteLine("KORD".CompareTo(testrecords[6].ident));
Console.WriteLine(String.Compare(testrecords[6].ident, "KORD"));
Console.WriteLine(String.Equals(testrecords[6].ident.Trim(), "KORD"));
output:
pre:
 False
 False
 False
 1
 -1
False
A number of methods that compare strings are returning False. My understanding of .CompareTo() and .Compare() are that it should return 0 if both strings are equal.

input:
pre:
String testString = testrecords[6].ident;
Console.WriteLine(testString);
Console.WriteLine(testString.Equals("KORD"));
Console.WriteLine(testString.Equals(testrecords[6].ident));
Console.WriteLine(testrecords[6].latitude_deg);
Console.WriteLine(testrecords[6].latitude_deg == 41.9786);
output:
pre:
"KORD"
 False
 True
 41.9786
 True
This is where it gets real hosed up - I set the value of testString to what's in testrecords[6].ident, and compare it to the string "KORD". It's False. I compare it to testrecords[6].ident and it's true. The last two lines are just me seeing if this happens with non-String comparisons.

As far as I can tell, this is an issue with FileHelpers - I've perused the documentation for it and can't seem to come up with any reason this should happen. I'm not putting it past me not knowing some specific C# horseshit, though - none of my programming friends are C#/.NET users. I've read this fun primer on comparing strings and feel like I'm not loving that up somewhere. It's the library that I picked that's loving up, right? I don't have brain worms, do I?

death cob for cutie
Dec 30, 2006

dwarves won't delve no more
too much splatting down on Zot:4
alternative to reading all that poo poo: is there a good library you recommend for parsing .csv files into objects for C#? that might just be more helpful at this point - FileHelpers was the first one I saw on StackOverflow and a friend recommended it to me based on memories of one college class

raminasi
Jan 25, 2005

a last drink with no ice

Epsilon Plus posted:

alternative to reading all that poo poo: is there a good library you recommend for parsing .csv files into objects for C#? that might just be more helpful at this point - FileHelpers was the first one I saw on StackOverflow and a friend recommended it to me based on memories of one college class

I’ve used CsvHelper before, and it’s Generally Fine. But so is FileHelpers - I’ve never encountered anything like what you’ve described. My money’s on some dumb “I was actually compiling the wrong project” error. But I’m phoneposting, so I can’t look in too much detail.

epswing
Nov 4, 2003

Soiled Meat
I’ve used CsvHelper for years, does the job I need it to do, well enough that I’ve never looked for another library.

Nuget:
https://www.nuget.org/packages/CsvHelper

GitHub:
https://github.com/JoshClose/CsvHelper

Star Warrior X
Jul 14, 2004

Epsilon Plus posted:

As far as I can tell, this is an issue with FileHelpers - I've perused the documentation for it and can't seem to come up with any reason this should happen. I'm not putting it past me not knowing some specific C# horseshit, though - none of my programming friends are C#/.NET users. I've read this fun primer on comparing strings and feel like I'm not loving that up somewhere. It's the library that I picked that's loving up, right? I don't have brain worms, do I?

Looks to me like it's the quotes. testrecords[6].ident is "KORD" and you're comparing it to KORD. Those are not the same. They're not even the same length.

death cob for cutie
Dec 30, 2006

dwarves won't delve no more
too much splatting down on Zot:4

Star Warrior X posted:

Looks to me like it's the quotes. testrecords[6].ident is "KORD" and you're comparing it to KORD. Those are not the same. They're not even the same length.

son of a bitch

edit: the console output when I print testrecords[6].ident didn't have an extra set of quotes in it so I presumed everything was fine

pre:
Console.WriteLine(testrecords[6].ident == "\"KORD\"");
this returns true

thank you for saving my sanity

death cob for cutie fucked around with this message at 16:30 on Mar 10, 2019

GI_Clutch
Aug 22, 2000

by Fluffdaddy
Dinosaur Gum
I've used FileHelpers in quite a few projects for work. Unless you actually want those double quotes in your properties, you should look into using the FieldQuotedAttribute. You can tell it what your quote character is, if it's always there, sometimes there, etc. based on your file format.

I'd assume you probably want to decorate your string properties with
code:
[FieldQuoted('"', QuoteMode.AlwaysQuoted)]

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I'm trying to use some reflection to expose some C# functions in my toy language interpreter. It looks like I should extract a MethodInfo to get to parameter bindings, but it seems clumsy.
code:
var methodInfo = type.GetMethod("SomeMethod")
Why do I have to use a string here? If I have the method in hand, is it possible to extract information about it and work with it dynamically directly? Is there function where I can give it the method and just get the junk from it? Something like:

code:
var methodInfo = SomeClass.SomeMethod.GetMethod()

Potassium Problems
Sep 28, 2001

Rocko Bonaparte posted:

I'm trying to use some reflection to expose some C# functions in my toy language interpreter. It looks like I should extract a MethodInfo to get to parameter bindings, but it seems clumsy.
code:
var methodInfo = type.GetMethod("SomeMethod")
Why do I have to use a string here? If I have the method in hand, is it possible to extract information about it and work with it dynamically directly? Is there function where I can give it the method and just get the junk from it? Something like:

code:
var methodInfo = SomeClass.SomeMethod.GetMethod()

Other than "That's just how the reflection APIs work" I dunno what to tell you, except you can and should use nameof instead of a magic string

code:
var methodInfo = type.GetMethod(nameof(SomeClass.SomeMethod));

Night Shade
Jan 13, 2013

Old School
You can use expressions too:
code:
Expression<Action> expr = () => SomeClass.SomeMethod(fake, args, here);
var methodInfo = ((MethodCallExpression)expr.Body).Method;
Or for an instance method:
code:
Expression<Action<SomeClass>> expr = instance => instance.SomeMethod(fake, args, here);
var methodInfo = ((MethodCallExpression)expr.Body).Method;
Doing it this way makes it a bunch easier to pick a specific overload, too.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

Night Shade posted:

You can use expressions too:
code:
Expression<Action> expr = () => SomeClass.SomeMethod(fake, args, here);
var methodInfo = ((MethodCallExpression)expr.Body).Method;
Or for an instance method:
code:
Expression<Action<SomeClass>> expr = instance => instance.SomeMethod(fake, args, here);
var methodInfo = ((MethodCallExpression)expr.Body).Method;
Doing it this way makes it a bunch easier to pick a specific overload, too.

Haha that's some shenanigans! So you're putting a dummy call for it into an AST and then just inspecting the root node to get the method information?

Night Shade
Jan 13, 2013

Old School

Rocko Bonaparte posted:

Haha that's some shenanigans! So you're putting a dummy call for it into an AST and then just inspecting the root node to get the method information?

Yup. The body is checked by the compiler and it gets handled the same way as if you declared a regular lambda by refactoring tools.

Adbot
ADBOT LOVES YOU

downout
Jul 6, 2009

Epsilon Plus posted:

alternative to reading all that poo poo: is there a good library you recommend for parsing .csv files into objects for C#? that might just be more helpful at this point - FileHelpers was the first one I saw on StackOverflow and a friend recommended it to me based on memories of one college class

EPPlus

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply