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
NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

GrumpyDoctor posted:

I thought that defining "async" methods that were just thin wrappers around Task.Run was considered bad practice?

Indeed, though moreso for public methods since it's better to let the caller choose whether or not to use Task.Run. If it's just a private helper method then it might not be so bad (depending on context).

Adbot
ADBOT LOVES YOU

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

It probably depends on what kind of resource is being disposed, but disposability and object pooling are not necessarily mutually exclusive. If an object implements IDisposable, but its lifetime lasts for the entire lifetime of the application, then you might never call Dispose on it (or only call Dispose on application shutdown) and that's fine. If the object is specifically designed to be short-lived, then you might run into trouble if you keep it alive in a pool, but there's nothing in the IDisposable interface that says it has to be short-lived.

Edit: VVVVVV Yeah, I should have stated the implicit assumption that if you're going to keep an IDisposable object alive in an object pool, then you're not calling Dispose when you return it to the pool.

NiceAaron fucked around with this message at 02:06 on Apr 1, 2016

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

If you want to keep the first method as async, this should work:

code:
public async Task<Foo> DoAThing(Bar aBar)
{
	// some async work with awaits and stuff that makes a Baz called baz eventually

	return await DoARelatedThing(aBar, baz);
}

public async Task<Foo> DoARelatedThing(Bar aBar, Baz aBaz)
{
	// some async work with awaits and stuff that creates a Foo called foo eventually

	return foo;
}
Basically, you need to tell DoAThing to wait for the task returned by DoARelatedThing to finish and use the result value. Otherwise you're working with the Task object itself instead of the result value.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

Just spitballing here, but if you have a "last modified timestamp" column on each table that the local database updates when a row is created or updated, then the local database can ask the Azure database "what's the latest timestamp you have for this customer" which should hopefully be faster than querying all of the data, and then only sync data that was modified after that timestamp.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

GetFooFromWebAsync is (presumably) written with the async keyword, so any exceptions it throws are bottled up inside the Task.

GetFoo is not written with the async keyword, so any exceptions bottled up inside the task are not unbottled, the Task containing the exception is just directly returned.

When the caller awaits the Task and the exception is unbottled (what a great word), you've already left GetFoo's try-catch block.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

I'm not really seeing where it goes against what ljw1004 was saying? ljw1004's statement is about throwing exceptions in async vs. non-async Task-returning methods, and your GetFoo method isn't the one throwing the exception.

It's the GetFooFromWebAsync method where it becomes relevant. Consider these two possible implementations:

code:
public async Task<int> GetFooFromWebAsync()
{
	if (someCondition) throw new Exception();

	await Task.Delay(100);
	return 1;
}

In this version, the exception is is bottled up inside the Task and only gets exposed when the Task is await-ed, so the non-awaiting GetFoo method won't catch it.

code:
public Task<int> GetFooFromWebAsync()
{
	if (someCondition) throw new Exception();

	return Task.FromResult(1);
}
In this version, the exception is thrown "eagerly", so it will get caught by the non-awaiting GetFoo method's try-catch block.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

B-Nasty posted:

You can also use the SQL Server NEWSEQUENTIALID function to get GUIDs that won't be all over the place and split pages, but that probably defeats the purpose, as client code won't be able to generate it pre-insert.

Unless you do something like this to generate the equivalent of NEWSEQUENTIALID in your client code:

https://blogs.msdn.microsoft.com/dbrowne/2012/07/03/how-to-generate-sequential-guids-for-sql-server-in-net/

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

chippy posted:

Entity Framework question. Formerly I've always used lazy loading, but for my current project, for performance, I've disabled lazy loading in favour of using explicit .Include() calls. However, this means I can no longer use Find() on the DbContext, and have to use SingleOrDefault() instead, if I want to use .Include()s. Doesn't this constitute a performance hit in itself? Is there a better way of using Eager Loading that I don't know about?

Did you measure a performance hit?

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

chippy posted:

Oh, I thought NiceAaron was asking if I'd measured a performance difference between .Find(id) and .SingleOrDefaultI(x => x.Id == id). I thought it was fairly commonly accepted that turning off Lazy Loading gave performance gains in a lot of cases.

I guess my real point was that if you've got two pieces of code, and you're wondering which one has better performance, there's a really easy way to get an unambiguously correct answer to your question: measure and compare the performance.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

fankey posted:

Given a list of IP addresses, I'm using the following to determine the first address to response with a valid HTTP response
code:
    static async Task<string> DownloadCheck(HttpClient client, string ip)
    {
      try
      {
        var rsp = await client.GetAsync( "http://"+ip, HttpCompletionOption.ResponseHeadersRead);
        if (rsp.StatusCode != System.Net.HttpStatusCode.OK) ip = null;
      }
      catch( TaskCanceledException)
      {
        // expected...
      }
      catch(Exception)
      {
        // not able to contact ip
        ip = null;
      }
      return ip;
    }

    static async Task<string> GetBestIpAsyncInternal(IEnumerable<string> ips)
    {
      using (HttpClient client = new HttpClient() { Timeout = TimeSpan.FromSeconds(2) })
      {
        IEnumerable<Task<string>> requests = ips.Select(ip => DownloadCheck(client, ip));
        Task<string> winner = await Task.WhenAny(requests);
        return await winner;
      }
    }
The issue is that if a given address fails and returns null before a valid response then my code returns null. Ideally I could call something like Task.WhenAnyEqual(requests, (ip)=> ip != null ) but such a thing doesn't exist. Any ideas how to accomplish this? I don't want to use Task.WhenAll because I don't want to wait around for some calls to timeout before returning a response.

Break it down into an easier problem: First write that WhenAnyEqual method, then you can use it. It should be easier to write if you're only thinking about Tasks, not http requests and so on.

I'm thinking that you could call Task.WhenAny in a loop. Each time Task.WhenAny completes, you check if the returned Task passes the condition. If it does, you're done. If it doesn't, remove it from the collection of Tasks and call Task.WhenAny again.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

NiceAaron posted:

Break it down into an easier problem: First write that WhenAnyEqual method, then you can use it. It should be easier to write if you're only thinking about Tasks, not http requests and so on.

I'm thinking that you could call Task.WhenAny in a loop. Each time Task.WhenAny completes, you check if the returned Task passes the condition. If it does, you're done. If it doesn't, remove it from the collection of Tasks and call Task.WhenAny again.

Since people are still discussing this (and I'm bored) I'll provide a more concrete code example of what I was thinking of (also untested and coding in the forum post text editor)

code:

public async Task<Task<T>> WhenAnyMatch<T>(IEnumerable<Task<T>> tasks, Func<T, bool> predicate)
{
	var collection = tasks.ToList();
	while (collection.Any())
	{
		Task<T> nextTask = (Task<T>)(await Task.WhenAny(collection));
		if (nextTask.Status == TaskStatus.RanToCompletion) // i.e. not cancelled or faulted
		{
			var nextResult = await nextTask;
			if (predicate(nextResult))
			{
				// This task matches the predicate
				return nextTask;
			}
		}

		// This task was either cancelled/faulted or it didn't match the predicate, so remove it from the collection and go back to the beginning of the loop to wait for the next one
		collection.Remove(nextTask);
	}

	// None of the task results matched
	return null; // or throw an exception, or return a Task<T> that returns default(T), or however you want to handle it
}

Using this method to solve the IP address problem is left as an exercise to the reader.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

Most likely ever-so-slightly different versions of the .NET framework.

Hell, the exact class is an implementation detail, so as long as it implements the interface it could return a different class with every call for all your code cares (or should care).

Edit: Since System.Linq.Enumerable+<ReverseIterator>d__74`1[System.Char] and System.Linq.Enumerable+<ReverseIterator>d__75`1[System.Char] appear to be the names of classes generated by the compiler for iterator blocks, it could be as simple as a method in System.Linq.Enumerable being added, removed, or moved around in the source code.

NiceAaron fucked around with this message at 06:19 on Feb 13, 2018

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

LongSack posted:

Didn't work :(

Oh well

Try deleting the .suo file for the project. There should be a hidden ".vs" folder in your solution folder; the path to the .suo file should be something like ".vs/{Solution Name}/{version}/.suo".

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

Supersonic posted:

So I've been working on a simple text RPG to help me learn C#, and I'm just wondering if this code looks okay. So far everything in the menus works (the options to fight a monster only appear once a character has been created save for the boss fight which I haven't fully implemented yet). My main issue is being confused as to whether or not I'm doing OOP right.

Is it a good idea to have the player class be static like I have? My rationale is that there's only one player (although I imagine this could change if you wanted to create a new character). Moreover, I'm a bit confused about inheritance. I imagine that the boss class should inherit the enemy class (bosses are enemies and have both HP and a name), but then the boss class should override the enemy HP variable and be set to a different (higher) value.

Finally, is the general logic right? I'm wondering if I should be having more functions return a result rather than things like Console.Writeline (to decouple methods from formatting)m, but if thats the case, where would the methods be returning to?

"There's only one of it" is a pretty bad reason to make a class static, and not just because you might change your mind later (though that's a pretty good reason on its own). If you implement Player as a static class then it's hard to reason about its behavior and how its state will change, because potentially any other piece of code in your program could be touching it and changing its state. If Player is a non-static class, then you know that the Player won't be affected by anything that doesn't have a reference to the Player instance, so it's easier to reason about. (Don't just make a public static field/property for your Player instance or it's no better than the static class!)

(Contrast with, for example, the System.Math class, which doesn't have any mutable state and therefore being static doesn't cause any problems.)

Avoid unnecessary levels of inheritance. If the only difference between a boss and a regular enemy is the name and HP, then just use the one Enemy class and pass different names and HP values to the constructor. You would only need inheritance if you wanted to override the code for one of the enemy class's methods. If you design your classes to be flexible then you can get different behavior out of them without inheritance. Another example: Currently your Combat class creates an instance of Enemy. If instead you pass in Enemy as a constructor parameter, then the same Combat class will be able to handle both regular enemies and boss enemies.

Another random piece of advice: Try to keep your nuts-and-bolts "mechanism" code separate from your higher-level "game logic" code. For example, in MainMenu.cs I see two places where you prompt the player to make a choice, and if they make an invalid choice you repeat the prompt in a loop until they make a valid one. (And you've tied the loop conditions to the Player, which makes it harder to reason about since you have to think about how each choice affects the Player object.) I could easily imagine similar logic being needed again and again as your program grows. If you created a method like:

code:
public static int PromptForChoice(params string[] choices)
{
	...loop until the user enters a valid choice...
}
then you could use it like:

code:
int menuChoice = PromptForChoice("Create a character", "Quit");
// At this point menuChoice is guaranteed to be a valid choice
switch (menuChoice)
{
	...
}
And now it's easier to see what's going on because the loop isn't in the way. If you separate your "mechanism" code from your "game logic" code like this, then your "game logic" will be more direct and to the point, and therefore easier to reason about and get right.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

I've used both Dapper and Entity Framework. Dapper is good because it's fast and simple and you can just write plain ol' SQL queries like you're used to. EF is good because using LINQ means that your queries are statically typed and verified by the compiler, which is cool as heck.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

hackbunny posted:

You outright can't use LINQ with Dapper, or is it just awkward?

Good question... I've never actually used LINQ with Dapper on any of the projects I've worked on. I do see from a quick 30-second Google search that LINQ extensions for Dapper do exist, but it's not clear to me whether they give you an IQueryable interface like EF does.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

a hot gujju bhabhi posted:

I use it primarily for its code style features, since I work a lot of inherited code and I like to try to bring it into line with good style while I work on it, having the highlighting from ReSharper is super handy for that.

Unrelated:

I'm used to ASP.NET MVCs handing of bundling and minification, where you could use a HtmlHelper to include the JavaScript and the internals would decide whether or not to render on script tag serving the minified concatenated JS, or render several tags serving each individual unminified file separately based on your environment. This was pretty useful because you essentially just threw your JS file paths into an array and let MVC handle the rest. It was all in the one place.

In ASP.NET Core MVC, they seem to have removed this in favour of using "environment" tags to render different script tags depending on the environment. The bundler ALWAYS bundles, and it's up to you to include either the bundled file or the individual files depending on the environment. This means every new file needs to be added to the bundle config, AND to the layout view. Is there a way to get the same behaviour as before?

I haven't done much with ASP.NET Core MVC yet, and I'm especially unfamiliar with the changes to bundling / minification, but I imagine it wouldn't be too hard to write a custom tag helper that reads the bundle config and does what you want. e.g. pass the output file name into the custom tag helper, and depending on the environment the custom tag helper decides to either render a single script tag for that output file, or parse the bundleconfig.json file to find the corresponding input files and render script tags for them.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

raminasi posted:

Wait, am I overly sleepy? As I read the comments the confusing behavior (at least to me) is that the base class apparently didn't get type-initialized by the call to GetById.

I regret to inform you that you might be overly sleepy. The base class Basic<Ya> did get type-initialized by the call to GetById, because GetById is a member of Basic<Ya>. Since there is no code anywhere in Basic<T> that adds to the instances dictionary, the instances dictionary is empty when GetById executes. The derived class Ya is not type-initialized because you haven't touched that class or any of its members by that point.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

You didn't share the compiler error but I'm guessing the problem is the unnecessary "new" operator.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

LongSack posted:

The “new” operator is used to create some new class from a LINQ expression. The idea is to take an IEnumerable<int> and produce an IEnumerable<(Protocol, int)>. select new ... is the normal way to do that with LINQ, but since the Protocol is not captured in the LINQ expression, I couldn’t figure out how to do that.

The "new" operator doesn't have any special meaning in a LINQ expression, it does the same thing that it does outside of a LINQ expression. You don't need the "new" operator to create a tuple. Compare with this line in your foreach loop:

code:
ret.Add((Protocol, port));
where you successfully create a tuple without using the "new" operator.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

Continuing the PDF talk from the previous page: I'm not sure how well this would work for a WPF application (in fact I suspect it probably wouldn't work very well at all) but something I've done in the past is generate HTML documents and then use headless Chrome to convert them to PDFs. In my case it was an ASP.NET MVC application so it worked very well, since it meant you could design and create the PDF files with the same html/css skills you were already using for the rest of the system.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

I'm not sure if I totally understood the overall problem, but if you do go the route of writing a bunch of similar methods with varying numbers of generic type arguments, consider writing a T4 template that spits out the code for all the overloads of your method. That solves the code duplication issue, because you're basically just writing the method code once in the T4 template. (At the cost of having to learn about and understand T4 templates...)

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

If nothing else, you can just make it a regular-rear end static method, have the default implementation call the static method, and then your specific implementation can call the static method too.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

FYI, creating a SOAP client is still supported in .NET Core - I've done it before. It's creating a SOAP service that is no longer supported.

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

I'm assuming the issue is that the fully qualified class names are ambiguous (i.e. the same namespaces are used in both assemblies), in which case one solution is to use the "extern alias" feature.

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias
https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#packagereference-aliases

Adbot
ADBOT LOVES YOU

NiceAaron
Oct 19, 2003

Devote your hearts to the cause~

I won't claim to have extensive experience with every way to generate PDFs from C#, but all the ones I've used sucked in some way compared to just using headless Chrome. Being able to preview and debug the HTML in a browser, and being confident that the resulting PDF will look the same when generated by your app, can be a huge advantage, depending on your needs.

Maybe setting it up is more effort than necessary, or maybe it's exactly as much effort as is necessary.

edit: And if your boss / client gives you fucky requirements like "I want this report to always fit on a single page, can you automatically shrink the font a bit if there's too much text?" you can write some Javascript code that does it.

NiceAaron fucked around with this message at 03:45 on Jan 11, 2024

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