Skip to main content

What is .NET Standard?

.NET Standard is one of many techs to emerge from the open source, cross platform .NET ecosystem. Compared to what’s come before, it’s simpler and way more effective. It may remove most, if not all, of the confusion surrounding cross platform NuGet packages. So what is exactly is it and how does it work? How does it relate to .NET Core?

Join Adam as he answers these questions, and takes a deep-dive into the magic behind the scenes.

🔗Transcription

00:00 Adam Ralph
This is my first time in the Ukraine, so I'm really very happy to be here. Thank you to the organizers for inviting me. Thank you to our sponsors for making it happen, and thank you to you all for coming to my talk. It's a great honor to be here. For those of you who don't know me, my name's Adam. I have been working with computery and codey type things since the early '80s. These gray bits on my beard kind of give that away a little bit. And these days, I work for a company called Particular Software, and we are the makers of NServiceBus. Has anyone here heard of either of these things? A few of you. Okay, that's great. That's good to know.
00:43 Adam Ralph
At the moment we're doing some really cool stuff around application monitoring, so if you're interested in that go ahead and have a look at this URL. Don't worry about trying to take photos of these URLs and write them down. I will publish the whole slide deck publicly straight after the talk. My Twitter handle is in the top right corner, so just watch there. I'll actually post the link to it there. I won't say much more about that.
01:11 Adam Ralph
What I will say is that Particular Software is a 100% remote-working company, so we all work at home. There is no physical office whatsoever, even the CEO works at home. That's really cool because it allows me to work in this. So, this is actually my second home. I spent the whole of last summer, and my girlfriend also works remotely. We spent the whole of last summer in this van, and that's one of the great benefits of remote working. So, if you're interested more in that, I will be doing a talk about that at some conferences later in the year.
01:49 Adam Ralph
Right, back to more relevant stuff. So, I look after a few NuGet packages. FakeItEasy is one of them. That supports .NET Standard 1.6. LiteGuard, that's a mocking library. LiteGuard is a guard clause library. It allows you to write things like Guard.Against.Null. That supports .NET Standard 1.0. xBehave.net is an xUnit extension. That supports .NET Standard 1.1. And lastly, NServiceBus, which is one of the main products of our company, and that currently, in RC, supports .NET Standard 2.0.
02:28 Adam Ralph
So, what is .NET Standard? Well, I think the best way to answer that question is to examine what the problem is that it's trying to solve. Back in the day, we had the .NET Framework, and Mono. Did anyone here use Mono much? Not many of you, so it's a great project, great goals and intentions. It largely meets those, but I think your mileage may vary a little bit. It never really made the mainstream but it's useful in some cases.
03:01 Adam Ralph
So in those days, things for very easy. You compiled through the .NET Framework and you ran on the .NET Framework, and that allowed you to run your applications on Windows, Windows Server, and using Mono, on Mac and Linux. Then, .NET Core came along. So .NET Core allows you to run your apps on Windows, Windows Server, Linux, Mac, and Tizen. Has anyone heard of Tizen? Couple of you. It's a thing by Samsung, it actually is an operating system for smart devices like TVs, smartwatches and things like that, and it has a .NET Core Runtime so you can run your applications there as well.
03:45 Adam Ralph
Then you've got things like Xamarin, so this allows you to run your .NET apps on things like iPhones, iPads, and Macs where you want a GUI. Then you've got Xamarin.Android, well that just runs on all the things. The amount of things that Android runs on is really enormous. All kinds of devices.
04:04 Adam Ralph
And then you've got UWP, none of the things. No, no, no, I'm being unkind. That runs on a number of things, Xbox One, the Hololens and exciting things like that.
04:18 Adam Ralph
So when you write a .NET application, you usually pull down some NuGet packages, right? It would be very unusual these days to write an application without using some kind of library, some kind of NuGet packages. The problem then is, at the beginning the NuGet gallery is full of packages written for the .NET Framework. So how do you then write applications for Xamarin, for .NET Core, for UWP? You want to be able to use the same kind of NuGet packages that you use on the .NET Framework.
04:52 Adam Ralph
So there was a solution for that called Portable Class Libraries. Anyone remember these? I think one hand went up, right. Good, because it wasn't a particularly pleasant space to work in. I actually call it the Portable Class Library fiasco. I'll explain why. Again, back at the beginning we had the .NET Framework 4.0. This is the old .NET Framework that we know and love. And later on, this thing called Silverlight came along. I actually misspelled this Sliverlight when I wrote this slide, but I thought I'd just leave it because Sliverlight sounds kind of more appropriate. And straightaway, we had this challenge that we wanted to use NuGet packages and libraries on the .NET Framework and Sliverlight.
05:47 Adam Ralph
So, there is an intersection of these two platforms, right? There are a number of APIs, classes, and methods and things, sitting in the middle here which do exist on both frameworks, so why not call that Profile14? I do not know where the 14 comes from, but that is the Portable Class Library Profile14. What that is is a set of reference assemblies that you can compile against which only contain the intersection of the .NET Framework and Silverlight.
06:24 Adam Ralph
Then, another framework appeared called .NET Core 4.5. Does anyone remember that? .NET Core 4.5, that was a thing at one point. Microsoft's versioning numbers are interesting, to say the least. But this did exist, and what that meant is that we had a number of new profile appearing. So, we had Profile5, which is the intersection of the .NET Framework 4.0 and .NET Core 4.5. We had the intersection of all three was Profile37. I don't know where these numbers come from, but that was called Profile37. There was no profile for the intersection of these two, for one reason or another. They just didn't produce that profile.
07:10 Adam Ralph
All right, all good so far, that kind of works. Then we introduced a fourth platform to the mix, and this is Windows Phone 8. And there is a fundamental problem with this diagram. Can anyone spot it? The clue's down here. The problem is that I've got nowhere to put Profile14. There is nowhere on this diagram that only represents the intersection of .NET 4.0 and Sliverlight 5.0. So this is embarrassing for me because I studied maths at university, so I should know this stuff. I thought I was drawing a Venn diagram here.
07:55 Adam Ralph
So, a Venn diagram is a diagram which shows the intersections of all the sets on the diagram, described by a British mathematician called John Venn in the 19th century. And it turns out that this isn't a Venn diagram, this is actually an Euler diagram. And an Euler diagram only shows the intersection of some of the sets on the diagram, described by a Swiss mathematician called Leonhard Euler in the, I think it was the 18th century. And this is another example of an Euler diagram, all right? So, I originally come from the UK, although I live in Switzerland now, so when someone asks me about where I come from, all I have to do is verbalize this very simple diagram and that explains it.
08:51 Adam Ralph
So, back to this thing. What we need is something else. This is not the right diagram. What we need is a four set Venn diagram, and it turns out that that is what this is. And we can apply our profiles to this, and now all of a sudden Profile14 has reappeared. And we've got this new one in the middle here, Profile136, the intersection of all of them.
09:18 Adam Ralph
So good so far, so we've got four platforms, right? And we've seen the profiles which intersects all of those. Now, this is a list of all the profiles that were available in PCL, and you can see down here we've actually got one, two, three, four, five platforms. And of course, it's not possible to draw a five set Venn diagram. Or so I thought.
09:47 Adam Ralph
So it turns out that this thing, this weird... it's a bit like a sausage inside of green bread roll or something, this is a five set Venn diagram, and you can get really silly with this. This is a six set Venn diagram, this is a seven set Venn diagram. Starting to look quite nice now. And actually, I think a number of years ago, in I think it was in 2012, a group of very clever people at the University of Columbia... University of Victoria, sorry, in British Columbia came up with the first-ever 11 set Venn diagram.
10:25 Adam Ralph
And if we apply our profiles back to this, I can't tell what's going on here anymore. But the problem is that this illustrates the complexity. So every time you add another framework to the mix, so we've got UWP 10 coming in here, and Windows Phone Application 8.1, whatever that was. It gets so complicated that you can't even diagram your PCLs anymore, your profiles. So that's why I'm saying this is a fiasco. It doesn't scale, right? The problem here is that every time you add a new framework you potentially double the amount of profiles available because you've got all the ones you had before, plus all those with that new framework in it, right? This doesn't scale, it explodes quadratically.
11:21 Adam Ralph
So, we needed a new solution for this, and the solution is, of course, .NET Standard. So .NET Standard doesn't have a logo, by the way, and I thought this would be really good, but the team didn't like it. But I'll try again. So, what .NET Standard does is it tries to do this. So, rather than trying to work out the intersection of all the different frameworks and working out all those different profiles and all the different possible combinations, what it does is it says, "Well look, there's a bunch of APIs, classes, methods, properties, et cetera, et cetera, which exist on all the platforms, right? There is a common intersection. And we're going to take that and we're going to call that .NET Standard. That bit in the middle."
12:17 Adam Ralph
In terms of versions of .NET Standard, they do this. So, .NET Standard 1.0 is the smallest intersection of all the platforms, and every single version of .NET Standard that comes out is a super set of the previous one, so it just gets bigger, and bigger, and bigger, and bigger. So it's fully backwards-compatible and the versioning scheme is very simple. Now what that means in terms of platform support is this. So you've got .NET Standard 1.0, which supports all these versions of all these platforms, .NET Standard 1.1, which supports all these versions but drops support for Windows Phone Silverlight 8.0. All the way through to the current version, which is .NET Standard 2.0. I wrote version silly here because this isn't just 10.1, it's like 10.0. and then a big string of numbers, so I just wrote... It made the diagram look really awkward because these columns weren't really wide, so I just wrote version silly, it's a silly version number.
13:23 Adam Ralph
But anyway, this shows you, for a particular version of .NET Standard, which platforms you will and will not support. Now, there's something slightly counterintuitive here. Us developers, we always like the latest, right? We always want to use the latest version of anything. That's the new and shiny, it's got to be the best. So naturally, what you do is, if you are producing a NuGet package or a library, you'd be tempted to target .NET Standard version 2.0. That's fine, but that means that someone using .NET Framework 4.6 would not be able to use your package. They've got to be using .NET Framework 4.6.1, or an older version. So your library will have the maximum amount of compatibility if you target .NET Standard 1.0.
14:21 Adam Ralph
Someone said to me that when they create a new library or a new package, the first thing they do is they target .NET Standard 1.0. When they find that .NET Standard 1.0 does not have some kind of class or method or something that they need, they move to .NET Standard 1.1 to see if that has it. So that's quite a good way to develop things, if you're concerned about maximum portability, maximum usage across platforms. Start with the lowest and work your way gradually up to the one which contains the APIs you need. I'll talk a bit more about that later.
14:59 Adam Ralph
Now, quick word about versioning. When .NET Standard was first announced, they wanted to do SemVer for their versioning. Now what that means is when you make a breaking change, you change your first version number. So you go from .NET Standard 1.6 to .NET Standard 2.0. Originally .NET Standard 2.0 was going to be a breaking change, so it was going to look like this. It was going to drop some APIs that were in .NET Standard 1.5 and 1.6, and it was going to be a breaking change. That's why they called it .NET Standard 2.0. However, the community was not very happy about that, and all kinds of noise was made on Twitter and other places, so that decision was reversed. .NET Standard 2.0 now is again a super set of .NET 1.6. But, the 2.0 remained. They wanted to communicate that this is a really major, big change. And actually, this diagram is more or less to scale. .NET Standard 2.0 is a lot bigger than .NET Standard 1.6. More detail on that in a minute.
16:18 Adam Ralph
You can actually... The documentation is great. You can see the diff between every single version of .NET Standard online if you go to URLs such as this. This is the difference between .NET Standard 1.4 and 1.3, and this is actually the smallest diff between all of them. So, all they've here is added a new class, another new class, and a couple of enum numbers, so it's a very small diff. But you can actually see the diff between all of them.
16:47 Adam Ralph
Now, how does this work? So, the first thing to do is to distinguish between the package and the application. When you create the package, what you do is you'd compile against this netstandard.dll, right? So this is your library here, you'd compile against netstandard.dll. And this contains all the classes, methods, properties, et cetera that exist in .NET Standard. And this is a completely empty library, okay? It actually has nothing in it. I can show you that quickly. Where are we? So, you can see here that this is... This is off. That this is the netstandard.dll here. And all it has is a bunch of empty classes and things, so if I go to, say, System.Array... It's just a bunch of empty methods.
17:50 Adam Ralph
So what that means is you never run against this assembly, you just compile against it and nothing else. You can get other things, like... See, this is interesting. Did you know that you could throw null? Having to throw an exception type is not a CLR restriction, that's a C# thing. So other languages might allow you to throw null. So clearly, this library wasn't written in C#, it couldn't have been. The compiler wouldn't allow this, but the CLR allows it. The reason for this is because whenever you have a property or a method which returns something, the CLR won't allow you to do nothing inside that method. You either have to return something or throw something. So the simplest thing that they could do here was to throw null.
18:40 Adam Ralph
But it doesn't matter because you never execute against this library, so you'll never have to try and catch null or anything like that. Now, when it comes to the application, things get slightly more complicated. So, here we've got a .NET Framework application referencing a .NET Standard class library. The .NET Framework application references the .NET Framework assemblies. That's simple, it's mscore.lib and things like that. The .NET Standard class library, as we saw before, references .netstandard.dll. However, this is not the .netstandard.dll that we saw in the previous diagram. That one was empty, this one is shipped by the .NET framework and what it does is it uses type forwarding. Has anyone heard of type forwarding? This has been around since the very early days of .NET. I think it was even in .NET 1.0.
19:42 Adam Ralph
If you look at a type in .NET, like system.object, system.object is not the identifier of the type. It's assembly name and then the name of the type, so it's like mscore.lib/system.object. That's the full identifier of type. It has an assembly, the place where it's actually located, built into it's identifier. So, the .NET Standard class library is looking for netstandard.dll/system.object. What netstandard.dll does is it says, "Oh hey, yeah. I've got system.object." When the runtime asks for it, it says, "Oh no, actually it's over here." It's actually mscore.libsystem/object." It just forwards the runtime to another assembly to look for that type, and that's type forwarding.
20:35 Adam Ralph
I'll show you that. I've got the netstandard.dll I'll open here. So you can see here, this is the .NET Framework 4.6.1 netstandard.dll, right? That is a different netstandard.dll to the one we saw. And this one does type forwarding, right? So you can see, every single type in here is forwarded to mscore.lib. So everything resolves at runtime. Does that make sense so far? Yeah, I see most of you nodding your heads, so that's great.
21:17 Adam Ralph
A little more work about .NET Standard 2.0. So, I said before that that was a major release, and it was for a couple of reasons. So, if we look at .NET Standard 1.x, that range, there was quite a bit of feedback from the community and it centered around two things, limitations and paralysis. I'll explain what I mean by that. .NET Standard 2.0, as I showed you, looks like this. Now, this intersection between the frameworks is pretty large, right? That's a very big intersection. .NET Standard 1.6 looked more like this. It was a much smaller intersection of the different frameworks. And the problem there was people complained because they were trying to move their libraries to .NET Standard 1.6 or a lower version, and they were saying, "Well look, the APIs that I need just aren't there. So the classes and methods that I need to make this library work are just not available."
22:19 Adam Ralph
So what the .NET Standard team did was they said, "Okay well, we're just going to give you more APIs. We're just going to give you a much bigger surface area. Now, that's had the interesting side effect of drawing these platforms closer together because if you have a larger common intersection, then all those APIs need to exist on all those platforms. There's a much larger overlap now between .NET Framework 4.61 and .NET Core 2.0. .NET Core 2.0 now has much more of the APIs that have always existed in .NET Framework 4.6.1. And the difference is vast. I think in .NET Standard 1.6, there are around 13-and-a-half thousand APIs, where an API is a method or a property, or one of those type of things, and in .NET Core and .NET Standard 2.0, it's around 33,000. So it's almost a 200% increase. It's a massive, massive difference.
23:17 Adam Ralph
And I showed you this diff between 1.3 and 1.4 earlier on. So this is the screenshot for GitHub. If you try and look at this for 2.0 versus 1.6, GitHub just gives up and says, "I can't show a diff that big," because it is so enormous. So, the idea now is that .NET Standard 2.0 contains pretty much all of the APIs that make sense on all different platforms. So it doesn't have things like system registry, for instance, because the registry only exists in Windows, makes no sense on Mac or Linux. But all the things that make sense on all the platforms, things like IDB connection, that didn't exist in .NET Standard 1.6. .NET Standard 2.0 has that because a database connection makes sense on all the platforms.
24:04 Adam Ralph
So, that hopefully largely takes care of those limitations that were complained about. Then there's paralysis. So, if I look at FakeItEasy, FakeItEasy depends on something called Castle.Core, and we wanted to move FakeItEasy to .NET Standard quite awhile ago, but we had to wait around six months for Castle.Core to support it first. Our hands were tied, we couldn't do anything until Castle.Core supported .NET Standard. Only then could we support .NET Standard.
24:40 Adam Ralph
If we look at, say we've got a RabbitMQ integration for NServiceBus. That depends on NServiceBus and it depends on the RabbitMQ client. NServiceBus, in turn, depends on Autofac and Newtonsoft.Json, right? So, these dependencies have actually been removed in the new version, the new RC, but the current version that's out there still depends on these. So, as you can see, in order to support RabbitMQ and NServiceBus, we need NServiceBus and RabbitMQ clients to support .NET Standard. We need NServiceBus, NServiceBus needs Autofac and Newtonsoft.Json to support .NET Standard, and so forth, and so forth. And these dependencies can get quite deep. You can have four or five levels of dependencies, and at the end you always have json.net.
25:30 Adam Ralph
So, the problem was that the community was paralyzed. They're all waiting for someone else to support .NET Standard before they could support it. So the answer to that is to reference anything. And I'll quickly show you this magic in action. So, I have here a solution. It has a .NET Core app and a .NET Standard library. So, in the .NET Standard library, I'm going to reference something called power collections, which is a really, really old library which only supports .NET Framework 2.0 from 2005. So it relies on the full .NET Framework, whereas this is a .NET Standard library. I'm going to go ahead and use this here. Now what I'm going to do is I'm going to reference the .NET Standard library from the .NET Core app. And if I go ahead and use that... Oops, I didn't want to do that. Couple of using statements... And if I run that, fingers crossed, it works.
27:06 Adam Ralph
So now we've got a .NET Core app calling into a .NET Standard library, calling into a .NET Framework library. So how does this magic work? Well, again, let's separate package from application. So in the package, we reference netstandard.dll, right? That's exactly what we had before. The .NET Framework class library is looking for mscore.lib in the .NET Framework assemblies. However, this is a different mscore.lib. It is a copy of mscore.lib that type forwards back to .NET Standard. If we then look at the application, things are again slightly more complicated.
27:53 Adam Ralph
We've got the .NET Core application referencing the .NET Core assemblies. We've go the .NET Standard class library referencing net standard. This is yet another version of net standard. This is a version of net standard that is shipped by .NET Core, and this version type forwards back to the .NET Core runtime assemblies. Then, of course, we've got the bottom of the chain. We've got our .NET Framework class library. That's looking for the .NET Framework assemblies. Again, this is another version of mscore.lib, shipped by .NET Core, and this one is type forwarding back to the .NET Core assemblies, right? So these assemblies are all using this type forwarding magic to make sure that everything here ends up back at the .NET Core runtime assemblies. Does that make sense?
28:55 Adam Ralph
Great, I see most of you nodding your heads. That's great, because it took me awhile to get my head around this. And I must admit, I always have to kind of look back at the diagrams to remind myself how it works, but it's pretty cool what you can achieve with this type forwarding magic. You can just kind of make this magical stuff happen at runtime.
29:14 Adam Ralph
Now, it's interesting to find out what happens if you take away this middle part here, right? We've got .NET Framework library here, .NET Core app. What if the .NET Core app directly referenced the .NET Framework assembly? I couldn't resist trying this. It's a bit kind of like on a side note because it's taken .NET Standard out of the equation, but if I try it let's see what happens. So I'm going to install PowerCollections directly into the .NET Core app. Okay, and I'm going to use it here. Couple of using statements, that looks fine. All right, so let's see if it compiles. Okay, it does compile. Who thinks this is going to work? Only two of you? Only three or four of you. Okay, you're very pessimistic, but let's see. It works.
30:29 Adam Ralph
The first time I saw that, I said, "Wow." This is a .NET Core app referencing a .NET Framework assembly directly. From 2.0 .NET Core, that just works. I found that pretty amazing, that you can do that. And if you look at this diagram, it kind of makes sense, right? You've got .NET Core referencing the .NET Core runtime, references .NET Framework assembly, this type forwarding magic points it back to the .NET Core runtime. It just works. Pretty cool.
31:04 Adam Ralph
So, give this a try. You need .NET Core 2.0 or greater. You need at least these versions. Don't worry, as I said, the slides are available online. These are the repos that I just showed you. There's another one which shows you what happens when... One of the questions I get asked is, "Well, what happens if the application calls something in the framework assembly, and that framework assembly tries to use something that doesn't exist in .NET Core?" That's a valid scenario. The answer is it just blows up. You get a NotImplementedException, so testing this kind of stuff is quite important if you're going to do it.
31:43 Adam Ralph
But that hopefully takes care of the paralysis. And that really is .NET Standard 2.0 in a nutshell. More APIs, reference anything. I put a star here because they only implemented this kind of type forward shimming for the .NET Framework in some PCL profiles. But they did an analysis of a NuGet gallery, and 70% of the packages on the NuGet gallery that target framework or PCLs just work in .NET Standard. So, that's why they thought that it's worth putting in this shimming mechanism.
32:17 Adam Ralph
Port my package, what do I do if I want to port my package? Well, you can check compatibility. If you want to move your package from .NET Framework to .NET Standard, dotnet-apiport is a really good tool. You can use it in Visual Studio by right-clicking and just going analyze project, or you can use it in the command line, and here I am running it against NServiceBus. And it produces, of all things, an Excel report. But you can configure it to output json, I think. And that gives you an output like this that says for NServiceBus.Core, this is for the current release version, not the RC, .NET Framework 4.5.2 has 100% of the APIs it needs. 1.6 has 66%, and 2.0 is 87%. So that's not far from 100%. We chose to target .NET Standard 2.0 for that reason.
33:13 Adam Ralph
So what do I do? What do I do to close that gap if there are APIs that I need that don't exist in .NET Standard? Well, you can change the way your library is written. You can use another set of classes and methods in .NET Standard, potentially. You can separate. This is really useful. In NServiceBus, we have MSMQ support built into it in the current version. MSMQ doesn't exist on Linux or Mac, so we separated that into a separate package, and if you want to use MSMQ, you install that package and then you're tied to Windows. But with our core package, you can use that on Linux and Mac, and use something else instead of MSMQ. Or you might, at the end, just choose to remove some stuff. You might have some old stuff in your library which you think no one uses, and you know no one uses, so you just remove it. But what we found was that separate was probably the most valuable one. We separated that Windows-specific functionality into another package.
34:15 Adam Ralph
APIs and version of .NET, really useful. You can use this to search for every single API that's ever existed on every single platform for .NET. Really, really useful resource. You search for DataReader, and it lists all the platforms it's supported on. We'll get to it eventually, there you go. So you can see where you might run into trouble and where you might not. There is an element of works on my machine here. So, some platforms do effectively cheat and they say, "Oh yeah, we support the .NET Standard," and there's a tiny subset of APIs that they don't actually support. So those will throw a PlatformNotSupportedException. But this is a list of all of them. There are very, very few of them, luckily, so that cheating is not going on too much.
35:12 Adam Ralph
.NET Standard versus .NET Core. Who here... I hope that I've demonstrated the difference between .NET Standard and .NET Core throughout this talk. .NET Standard is more of a contract that you compile against. .NET Core is just one of the platforms. So you've got .NET Standard, then you've got .NET Framework, Xamarin, UWP, .NET Core. It's just one of those platforms. But there has been, historically, a lot of confusion between the two, and in fact, if you look at some of the .NET Core documentation, you'll get things like this, the .NET Standards release schedule, but you'll actually see this. You'll see .NET Core and .NET Standard kind of munged together into one. So there's a lot of documentation and stuff out there which conflates the two together, and the reason for that is because .NET Core drove a lot of the development of .NET Standard. But .NET Core is just another one of those platforms.
36:16 Adam Ralph
This is another way of visualizing, this is something that David Fowler put together. He's actually got interfaces for each version of .NET Standard, and then interfaces for each version of the platforms, and shows which one inherits from another. I hope I haven't just confused you by showing you that, but it's another useful way to visualize it. Some people find that really quite intuitive.
36:43 Adam Ralph
.NET Standard 2.1, 2.2 or 3.0? So, this is interesting. Will there be a .NET Standard 2.1? I'm almost certain there will be. There's not one, I haven't heard about one yet, but I think eventually there will be some new APIs recognized that are being added, say, to .NET Core. .NET Core is kind of revving fastest in the area, and these may well make their way back to .NET Standard and a 2.1. 3.0, I'm a bit more skeptical about. I'm not sure we'll ever need a .NET Standard 3.0. I think Microsoft will ever break, so that won't be a reason to go to 3.0, and I'm not sure there'll ever be such huge step change as there was from 1.6 to 2.0 because 2.0 should theoretically contain most of the APIs we're going to need across all the different platforms.
37:36 Adam Ralph
So, how did I do? Who here believes that they kind of understand what .NET Standard is all about now? Hands are slowly going up, yeah I think I've just about got half. Who thinks they understand the different between .NET Core and .NET Standard? Oh, that's almost all of you. Awesome, job done. I didn't ask you that question when you came in, of course, but I hope that I helped there a little bit.
38:06 Adam Ralph
Before we wrap up, I might have time, maybe one question, or maybe a couple. Yeah.
38:12 Speaker 2
I've got a question. Here.
38:26 Speaker 2
Yes, so the question is about this type forwarding. Is there any performance penalty, performance...?
38:33 Adam Ralph
Thank you, you haven't let me down because so far, someone's always asked me that question. Thank you very much. Is there any performance penalty in type forwarding? I think, strictly speaking, the answer is yes, right? So nothing comes for free. However, type forwarding has been around since .NET 1.0, well certainly .NET 1.1, I should check on 1.0 but it was in there right at the beginning. And I think most of us didn't really start using .NET in anger until 2.0 and later. So, type forwarding is in the .NET code you run right now. If you write a "Hello World", it's likely that some type forwarding is happening underneath in the CLR. So, I think strictly speaking, the answer is yes there's a performance penalty. Is it significant? No. And I think that you're talking about micro, micro performance hits.
39:31 Adam Ralph
How are we doing for time? So maybe one more quick question before we wrap up.
39:41 Adam Ralph
Okay, well if there's nothing, that's fine. I will be in the speaker's corner at half past four, so I'll be more than happy to answer questions there. If you're interested more in this NServiceBus thing I've been talking about, there's some interesting stuff here if you want to see what NServiceBus is and what we're doing around the .NET Core support. So that might give you some insight into how we've dealt with the .NET Standard problem.
40:07 Adam Ralph
So, I guess that's it, so I've really enjoyed talking to you. I hope I've cleared up some of the mystery about what .NET Standard is and its relationship to .NET Core and the other platforms. I will be around for the rest of the day. I'll be in the speakers corner at half past four, so I look forward to talking to you. And thank you very much for listening.