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
New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Dolemite posted:

Yeah, I definitely saw lambdas all over the place within the codebase at the last company. Oddly, I never once saw any lines of code containing Action<T1, T2> or Func<T, TResult>. Took a look at the C# reference docs and these are interesting. They're referred to as delegates, which makes sense. The way Action and Func are used in the code samples, it's almost like you use the Action or Func to describe a method signature. Then, attach your concrete function - with matching parameter list - like a callback. Am I in the ballpark?

The first line here - is this pretty similar to, if not exactly, dependency injection? I've briefly read about IoC before, but every explanation is written for Comp Sci people. I'm self taught, so chunks of it fly over my head. Even poo poo from the MS docs (I keep having to google Big O notation when I see it in the docs).

Actions and Funcs are basically anonymous methods. An Action is an anonymous method that is void (i.e. returns nothing). A Func is an anonymous method that returns a value. In essence, it allows you to pass chunks of code around as method parameters.

Dependency injection is a method of achieving inversion of control. It's also among the most common methods, so if you're familiar with dependency injection, you're pretty well set on IoC.

Adbot
ADBOT LOVES YOU

insta
Jan 28, 2009
Dolemite you're going to do fine in .NET. You clearly show enough aptitude that any decently competent interviewer will let you reason yourself into the answer they want to hear (your thinking along Func/Action sold me).

Now go learn that var is good and is not dynamic and you're golden.

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer

insta posted:

var is good

Oh, I see we are going to have to fight today...

(I jest ofc, but I usually insist on avoiding var)

raminasi
Jan 25, 2005

a last drink with no ice

Canine Blues Arooo posted:

Oh, I see we are going to have to fight today...

(I jest ofc, but I usually insist on avoiding var)

Hopefully we can all eventually come together to agree that whatever you decide to do, do it consistently.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

raminasi posted:

Hopefully we can all eventually come together to agree that whatever you decide to do, do it consistently.

Sure, do it consistently the way I like to do it.

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer

New Yorp New Yorp posted:

Sure, do it consistently the way I like to do it.

you goddamn right.

LongSack
Jan 17, 2003

Just curious - what are the objections to using var? I never used it until several months ago when I started adding Microsoft’s fxcop analyzer to my projects, and it definitely recommends using it.

It saves some keystrokes when declaring say an ObservableDictionary<Foo, List<Bar>>

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer
My major beef with it is code readability / observing data flow, in addition to having a full understanding of how things work.

For example, I just implemented language detection in a project with NTextCat. The code example provided looks like this:

code:
var factory = new RankedLanguageIdentifierFactory();
var identifier = factory.Load("Core14.profile.xml"); // can be an absolute or relative path. Beware of 260 chars limitation of the path length in Windows. Linux allows 4096 chars.
var languages = identifier.Identify("your text to get its language identified");
var mostCertainLanguage = languages.FirstOrDefault();
if (mostCertainLanguage != null)  
    Console.WriteLine("The language of the text is '{0}' (ISO639-3 code)", mostCertainLanguage.Item1.Iso639_3);  
else 
    Console.WriteLine("The language couldn’t be identified with an acceptable degree of certainty");
That is nice, but it's also borderline interpreted nonsense for understanding what's actually happening here and how this library is constructed.

We can easily identify factory as type RankedLanguageIdentifierFactory, but what the hell is identifier? Or languages...? We are calling FirstOrDefault on languages, so that's a clue, but it also doesn't narrow it down much. The point here is that if I were maintaining this code, understanding what I'm actually working with requires a bunch of extra time because I'm effectively eschewing one of the major advantages of a strongly typed language by not letting the reader know what these things actually are.

Compare to:

code:
RankedLanguageIdentifierFactory factory = new RankedLanguageIdentifierFactory();
RankedLanguageIdentifier identifier = factory.Load("Core14.profile.xml");
IEnumerable<Tuple<LanguageInfo, double>> languages = identifier.Identify("your text to get its language identified");
Tuple<LanguageInfo, double> mostCertainLanguage = languages.FirstOrDefault();

if (mostCertainLanguage != null)  
    Console.WriteLine("The language of the text is '{0}' (ISO639-3 code)", mostCertainLanguage.Item1.Iso639_3);  
else 
    Console.WriteLine("The language couldn’t be identified with an acceptable degree of certainty");
Immediately there is a lot more information here available to the maintainer. Besides understanding explicit how things are constructed (factory loads an indentifier of type RankedLanguageIdentifier, which is applied to a string that returns IEnumerable<Tuple<>>...), a lot of functionality is immediately communicated. languages is IEnumerable<T>, which means this is actually returning a collection with a specific kind of functionality. Tuple has specific functionality I can use as well. I get all this information without having to start mousing over functional calls on a first read, and it's also easy to reference if I need to look up type information about a specific variable. This is all lost (or at least obfuscated) using var in the name of saving keystrokes, which in my head is a pretty weak reason to not create code that's easier to maintain.

This is also a fairly simple, self-contained example. The problem of readability and maintainability expands a lot as one expands the scope of a project.

GI_Clutch
Aug 22, 2000

by Fluffdaddy
Dinosaur Gum

LongSack posted:

Just curious - what are the objections to using var? I never used it until several months ago when I started adding Microsoft’s fxcop analyzer to my projects, and it definitely recommends using it.

It saves some keystrokes when declaring say an ObservableDictionary<Foo, List<Bar>>

I've seen code examples where it is used for everything. Like:
code:
var i = 1;
var input = Console.ReadLine();
I'd use int and string there as it makes it more readable. Sure, I can tell that's an int and string from looking at it, but that just feels lazy IMO. But nothing wrong with using it to define a generic or anything else where you'd just be repeating yourself on the same line.

No Pants
Dec 10, 2000

One of the objections I've heard even when the type is explicit on the right side of a declaration is that it can feel weird in some way for left-to-right readers. C# 9.0 adds target-typed new expressions, so pedants will have a new dimension of opinions to inflict on each other in a few days.
code:
Butt b = new Butt();
var b = new Butt();
Butt b = new();

B-Nasty
May 25, 2005

Canine Blues Arooo posted:

My major beef with it is code readability / observing data flow, in addition to having a full understanding of how things work.


If you're using an IDE like VS, hovering over the variable will give you its type. I think Rider/R# has an option to show the type as a hint.

var is better, if it leads to using longer/more descriptive variable names. I'd much rather see:

code:
var usersGroupedByUserId = ...
than
code:
Dictionary<int, List<User>> users = ...

raminasi
Jan 25, 2005

a last drink with no ice

B-Nasty posted:

If you're using an IDE like VS, hovering over the variable will give you its type. I think Rider/R# has an option to show the type as a hint.

var is better, if it leads to using longer/more descriptive variable names. I'd much rather see:

code:
var usersGroupedByUserId = ...
than
code:
Dictionary<int, List<User>> users = ...

While I am personally a var-everywhere guy, I have to admit that it can easily become a pain in the rear end when you don't have an IDE right there, like during code reviews.

redleader
Aug 18, 2005

Engage according to operational parameters
a compromise i like is using var when the type of the rhs is clear (e.g. var foo = "bar"; var bar = 1m; var baz = new Dictionary<ValueTuple<int, long, long>, List<HashSet<string>[]>>()), and explicitly writing the type when it isn't

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer

raminasi posted:

While I am personally a var-everywhere guy, I have to admit that it can easily become a pain in the rear end when you don't have an IDE right there, like during code reviews.

Code Reviews are definitely a common use case where it gets obnoxious, but for complex structures, constantly having to mouse over stuff is a mental drain. Do you really want to have to mouse over stuff to see it's type, or would you rather it always be right there?

insta
Jan 28, 2009
I'm an always-var after being stymied at big refactors because of things like this:

code:

public IList<string> GetFoos() { ... }
//to
public IEnumerable<string> GetFoos() { ... }

This kind of thing works fine if all the consumers are "var" to the method. But, it's super common (and advocated by the thread!) to do this:

code:
List<string> values = GetFoos();
//instead of:
var values = GetFoos();
Keeping things as var across my (large) projects really does allow for faster and more seamless refactoring.

B-Nasty
May 25, 2005

Canine Blues Arooo posted:

Code Reviews are definitely a common use case where it gets obnoxious, but for complex structures, constantly having to mouse over stuff is a mental drain. Do you really want to have to mouse over stuff to see it's type, or would you rather it always be right there?

That would be the point of using descriptive variable names. If the variable (and function returning its value) are named well, I don't find the type adds much additional info. The example you had from NTextCat is a good example of bad variable names.

Having a well-named variable continues to pay you back if the variable is used again and again. I'd rather not have to remember the type from when it was declared. I've found having the long type starts to eat too much into line length, and encourages a short, crappy variable name, thus reinforcing the problem.

Canine Blues Arooo
Jan 7, 2008

when you think about it...i'm the first girl you ever spent the night with



Grimey Drawer
I don't disagree, but how you are going to descriptively name a Tuple<LanguageInfo, double> that implies it's type, or name something of an arbitrary type e.g. RankedLanguageIdentifier . I'd argue it's a 'both' kind of a thing, not one or the other.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
A decade or so ago, ReSharper insisted I slap var everywhere and it broke my brain.

LongSack
Jan 17, 2003

OK, I can see that.

There’s a readability difference in var Foo = new ...() and var Foo = someObject.someMethod().

MadFriarAvelyn
Sep 25, 2007

I used to advocate for using var only in situations where it was obvious what type was being assigned based on the right hand side of the statement and/or a built in .Net method that was likely to be more stable over a given period of time.

Now I just convert entire source files into a binary representation where whitespace indicates 0 and var indicates 1. Now my source code is :suicide:

adaz
Mar 7, 2009

Do people who advocate for var everywhere ever use Java? Because that's what not getting var gets you.

I prefer using var in all cases where it's obvious -- i.e. var person = db.CreatePerson(); . Else you coed just looks.... gross.

insta
Jan 28, 2009
sorry your variable names and ide suck

redleader
Aug 18, 2005

Engage according to operational parameters

insta posted:

I'm an always-var after being stymied at big refactors because of things like this:

code:

public IList<string> GetFoos() { ... }
//to
public IEnumerable<string> GetFoos() { ... }

This kind of thing works fine if all the consumers are "var" to the method. But, it's super common (and advocated by the thread!) to do this:

code:
List<string> values = GetFoos();
//instead of:
var values = GetFoos();
Keeping things as var across my (large) projects really does allow for faster and more seamless refactoring.

that should break though

brap
Aug 23, 2004

Grimey Drawer
var is good and if the readability problem bothers you, you should know that the Roslyn team is adding a feature to VS to show the implicit types of things like var and lambda parameters, as well as method argument labels in some cases IIRC.

redleader posted:

that should break though

I’m not sure I agree, changing the return type of a method is often done because of some arbitrary issue related to what specific container or whatever is needed, if the poo poo has all the things I want I am happy to be left alone and have the churn reduced.

Another way to say this is: why is ‘var x = M1(); x.M2();’ not ok but ‘M1().M2()’ is totally fine

NihilCredo
Jun 6, 2011

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

redleader posted:

that should break though

Why? If you're not invoking any List-specific method or property, or if you're not passing it to a function that expects specifically a List, then your code shouldn't care.

If you're only invoking .Count(), for example, then your local code was effectively fine taking in any IEnumerable (and if it had been turned into a named function, it would have taken an IEnumerable parameter).

Canine Blues Arooo posted:

Code Reviews are definitely a common use case where it gets obnoxious, but for complex structures, constantly having to mouse over stuff is a mental drain. Do you really want to have to mouse over stuff to see it's type, or would you rather it always be right there?

This is why Visual Studio and VS Code show types as automatic CodeLens annotations in F# (where type inference is even more pervasive than 'var') :

(the grey comments aren't real text, they're just IDE annotations)



Obviously that's even more IDE reliance, and won't solve the code review problem (unless your IDE has a plugin for your VCS server that lets you do inline code reviews).

Then again, C# is not exactly a Notepad-friendly language no matter how many QoL features you eschew.

Canine Blues Arooo posted:

I don't disagree, but how you are going to descriptively name a Tuple<LanguageInfo, double> that implies it's type, or name something of an arbitrary type e.g. RankedLanguageIdentifier . I'd argue it's a 'both' kind of a thing, not one or the other.

Tuples should usually not be named at all, in recent versions of C# (or in F#) you can deconstruct them right there in the declaration:

code:
var (mostCertainLanguageInfo, languageScore) = languages.FirstOrDefault();
I used tuples a few times in VB.NET, where deconstruction wasn't available, and settled on a very un-idiomatic but still IMO quite readable alternative:
code:
Dim mostCertainLanguageInfo__languageScore = languages.FirstOrDefault

NihilCredo fucked around with this message at 11:33 on Nov 10, 2020

Mata
Dec 23, 2003

redleader posted:

that should break though

:agreed:
Changing the return type of a function will propagate in unexpected ways if you overuse var. Usually this will cause compile errors that can be traced back to the var assignment, sometimes you'll be unlucky and the ramifications don't make themselves known until runtime. IMHO it's a loss of type safety. That said, I'll use var in a project that has the prefer-var lint rule, i just don't add that rule to my own projects.

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
I only avoid var for primitive types like int, double and string. Using var for those looks wrong to me. Otherwise it's var all the time every time.

Mata posted:

:agreed:
Changing the return type of a function will propagate in unexpected ways if you overuse var. Usually this will cause compile errors that can be traced back to the var assignment, sometimes you'll be unlucky and the ramifications don't make themselves known until runtime. IMHO it's a loss of type safety. That said, I'll use var in a project that has the prefer-var lint rule, i just don't add that rule to my own projects.

I haven't ever had this happen to me (specifically in relation to the use of var). But that might be because I haven't worked on the kind of project where that's a thing that can happen. Can you give an example?

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
More WPF: I set up the list choices for the dialog box I'm working on and the text is getting cut off when I use it:

[The Yes/No]



I was being pretty bad about putting child elements inside the border tags, and I figured that would fix it, but it had no effect. Does anything else look obviously wrong? Here's a pastebin (50 lines)



Regarding var: The most compelling justification I got for it was that most of the code doesn't have to care if something is a specific type or not so long as it has all the named things it's trying to do. So if you change foo.bar() in var x = foo.bar() to return something else, the code merrily hums along without having to change the types.

You could subvert this argument by deciding to just use dynamic everywhere then. I wanted to post something cute here in spoilers where I just slapped dynamic on everything, but I think this would be the day one of you invented something that sends fists across the Internet and hit me with it.

I tried to do a similar experiment using auto types for personal C++ work, but the tools had a much harder time telling me what stuff was when I was having a problem so it got frustrating. This was back in 2012 and I'd like to hope things have improved (please don't tell me the bad news).

insta
Jan 28, 2009
The difference is that dynamic actually sucks though

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
You're right but it does take everything to its illogical conclusion!

biznatchio
Mar 31, 2001


Buglord
You should only be using dynamic in extremely specific situations; and foremost among those are some forms of COM interop, some forms of interop with objects given to you by a scripting engine, and some cases where you need to process arbitrarily-shaped JSON objects. And even in these cases there's often a better way you should be doing it instead.

You should never be in a situation where you're looking at a var keyword and thinking "boy I should change that to dynamic", because var and dynamic fill entirely different purposes. Unless you can explain in detail why the actual contract of an object won't be known until runtime and why using adapter classes and interfaces isn't suitable, then dynamic is the wrong solution.

At least, if your intention is to write performant, robust, and maintainable code, that is. If you're just making GBS threads out a quick utility that'll be used a few times and never seen again, then by all means go hog wild.

mystes
May 31, 2006

If I'm remembering correctly, even with COM interop, you don't generally need to use dynamic if you use a PIA which you probably should if you can, so it's extremely rare to have a case where you need to use dynamic unless you're just messing around with COM objects using c# like a scripting language.

raminasi
Jan 25, 2005

a last drink with no ice
I have also never seen the theoretical “var can cause incorrect type propagation during refactors that causes bugs” argument actually play out in practice. You’d need two different types with nominally matching contracts but different semantics. I can maybe imagine some problem with asymptotic complexity? Never run into one though.

Re: dynamic: You can also use it to get multiple dispatch, if you ever happen to need that. I never have but it’s a spooky little corner of the language.

rarbatrol
Apr 17, 2011

Hurt//maim//kill.
I've run into the var + refactoring issue once, but it was long ago so I don't have a concrete example. It may have been async/await related?

CapnAndy
Feb 27, 2004

Some teeth long for ripping, gleaming wet from black dog gums. So you keep your eyes closed at the end. You don't want to see such a mouth up close. before the bite, before its oblivion in the goring of your soft parts, the speckled lips will curl back in a whinny of excitement. You just know it.
I've got a brain teaser here and I could use some extra ideas. I need to connect to an API run by a third party. To do that, I'm using this code:
code:
string url = apiURL;

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(String.Format("{0}{1}", url, ""));
request.ContentType = "application/json";

string APIkey = APIkey;
string authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(APIkey));
request.Headers["Authorization"] = "Basic " + authInfo;

using (StreamReader stream = new StreamReader(request.GetResponse().GetResponseStream()))
{
	string response = stream.ReadToEnd();
	stream.Close();
	List<Dictionary<string, object>> output = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(response);
}
In my scratchpad app where I test new code, a winforms app running .NET 4.6.1, this works perfectly. When I copy and paste this exact code to where it needs to be, a web service running .NET 4.7.2, it errors out on the "using StreamReader" line, with error "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host."

I added the following lines right before the stream gets opened, because I'm just trawling StackOverflow and throwing in anything that's ever worked for anyone at this point:
code:
request.KeepAlive = true;
request.ProtocolVersion = HttpVersion.Version10;
request.ServicePoint.ConnectionLimit = 24;

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
System.Net.ServicePointManager.Expect100Continue = false;
None of it's helped. Can anyone think of any more reasons why perfectly good code would also be code that doesn't work?

Faldoncow
Jun 29, 2007
Munchin' on some steak

Rocko Bonaparte posted:

More WPF: I set up the list choices for the dialog box I'm working on and the text is getting cut off when I use it:

[The Yes/No]

Your inner Grid (1*, 5*, 1* rows) has a certain amount of space that it can take up, based on the parent Grid (which is given 1/3 of the parent space based on the outer grid). The bottom row gets 1/7th (1* out of 7*) of the vertical space, which at the available space is not enough pixels to display the Yes/No choices at their given font size.

Recommended solution: Use a Dockpanel for the inner grid, instead of a grid. Dockpanels are pretty great. They'll assign elements only as much space as they need, and then the last element in order gets all the remaining space. This means you can give the title and bottom choices list their required space, and then let the description fill the remainder.

code:
<DockPanel>
	<TextBlock DockPanel.Dock="Top" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Title}"/>
	<Border DockPanel.Dock="Bottom">
		<ListBox Name="ChoicesList" Background="#00000000" Foreground="White" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" ItemsSource="{Binding Choices}">
			<ListBox.ItemsPanel>
				<ItemsPanelTemplate>
					<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"/>
				</ItemsPanelTemplate>
			</ListBox.ItemsPanel>
		</ListBox>
	</Border>

	<TextBlock DockPanel.Dock="Top" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding Text}"/>
</DockPanel>
Alternatively you can use a Grid, but give the Title and Choices rows "auto" RowHeight and the Text/Body "1*".

mystes
May 31, 2006

.NET 5 is out.

SirViver
Oct 22, 2008

CapnAndy posted:

I've got a brain teaser here and I could use some extra ideas.
I'm 99% sure this is a TLS issue. The main difference between .NET versions <= 4.6.1 and newer ones is that with newer versions they've more and more switched to just using the TLS configuration settings of the OS instead of having any logic or protocol versions hardcoded. Presumably what happens when you target the newer .NET FW is that it uses more recent protocol versions configured in Windows (respectively outright proactively rejects older ones) and the endpoint you're trying to connect to only supports an older one. (Or it's the other way round and your OS is setup in an insecure way that forces old TLS, but that requires active registry fuckery.)

A pretty detailed explanation can be found here: Transport Layer Security (TLS) best practices with the .NET Framework

But a better way than trying various settings randomly is enabling System.Net network tracing. The logs aren't necessarily easy to read, but in there you should find mentions regarding which TLS versions it allows for connections on your side and also which ones are supported by the host... probably. It's been a while since I last did this, so I'm not 100% sure of the details, but in either case it should give you enough info to figure out what the actual problem is.

epswing
Nov 4, 2003

Soiled Meat

mystes posted:

.NET 5 is out.
This is cool:
C# code:
if (threshChoice.KeyChar is 'Y' or 'y')
But what the hell is this:
C# code:
if (pollingType is not { Length: >15 })
Also, single file applications, it's about time.

Adbot
ADBOT LOVES YOU

CapnAndy
Feb 27, 2004

Some teeth long for ripping, gleaming wet from black dog gums. So you keep your eyes closed at the end. You don't want to see such a mouth up close. before the bite, before its oblivion in the goring of your soft parts, the speckled lips will curl back in a whinny of excitement. You just know it.

SirViver posted:

I'm 99% sure this is a TLS issue.
I've since copy and pasted the code into a 4.7.2 console app and it runs fine there, does that change your opinion at all? That's my current cop-out solution, just make a console app that works and have the web service run the console app.

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