The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,854 other subscribers

Archive for the ‘.NET’ Category

VS2017 Community .vsconfig file – Visual Studio Community workload and component IDs | Microsoft Docs

Posted by jpluimers on 2021/03/10

When I need to find out what components match my below installed .vsconfig component IDs for Visual Studio 2017 community edition, I can find them in: [WayBack] Visual Studio Community workload and component IDs | Microsoft Docs: Use workload and component IDs to install Visual Studio by using the command line or to specify as a dependency in a VSIX manifest.

{
    "version": "1.0",
    "components": [
        "Microsoft.VisualStudio.Workload.ManagedDesktop",
        "Microsoft.VisualStudio.Workload.NativeDesktop",
        "Microsoft.VisualStudio.Workload.Universal",
        "Microsoft.VisualStudio.Workload.NetWeb",
        "Microsoft.VisualStudio.Workload.Azure",
        "Microsoft.VisualStudio.Workload.Python",
        "Microsoft.VisualStudio.Workload.Node",
        "Microsoft.VisualStudio.Workload.Office",
        "Microsoft.VisualStudio.Workload.NetCrossPlat",
        "Microsoft.VisualStudio.Workload.VisualStudioExtension",
        "Microsoft.VisualStudio.Workload.NativeCrossPlat",
        "Microsoft.VisualStudio.Workload.NetCoreTools",
        "microsoft.net.componentgroup.targetingpacks.common",
        "microsoft.visualstudio.component.entityframework",
        "microsoft.visualstudio.component.debugger.justintime",
        "microsoft.visualstudio.component.vc.diagnostictools",
        "microsoft.visualstudio.component.vc.cmake.project",
        "microsoft.visualstudio.component.vc.atl",
        "microsoft.visualstudio.component.vc.testadapterforboosttest",
        "microsoft.visualstudio.component.vc.testadapterforgoogletest",
        "microsoft.visualstudio.componentgroup.web.cloudtools",
        "microsoft.visualstudio.component.aspnet45",
        "microsoft.component.azure.datalake.tools",
        "microsoft.visualstudio.componentgroup.azure.resourcemanager.tools",
        "microsoft.visualstudio.componentgroup.azure.cloudservices",
        "microsoft.visualstudio.component.azure.mobileappssdk",
        "microsoft.visualstudio.component.azure.servicefabric.tools",
        "microsoft.component.cookiecuttertools",
        "microsoft.component.pythontools.web",
        "component.cpython3.x64",
        "microsoft.visualstudio.component.teamoffice",
        "component.google.android.emulator.api27",
        "component.linux.cmake"
    ]
}

This comes in very useful when installing Visual Studio 2017 through chocolatey:

chocolatey install -yes visualstudio2017community
:: "Microsoft.VisualStudio.Workload.ManagedDesktop", 
chocolatey install -yes visualstudio2017-workload-manageddesktop
:: "Microsoft.VisualStudio.Workload.NativeDesktop", 
chocolatey install -yes visualstudio2017-workload-nativedesktop
:: "Microsoft.VisualStudio.Workload.Universal", 
chocolatey install -yes visualstudio2017-workload-universal
:: "Microsoft.VisualStudio.Workload.NetWeb", 
chocolatey install -yes visualstudio2017-workload-netweb
:: "Microsoft.VisualStudio.Workload.Azure", 
chocolatey install -yes visualstudio2017-workload-azure
:: "Microsoft.VisualStudio.Workload.Python", 
chocolatey install -yes visualstudio2017-workload-python
:: "Microsoft.VisualStudio.Workload.Node", 
chocolatey install -yes visualstudio2017-workload-node
:: "Microsoft.VisualStudio.Workload.Office", 
chocolatey install -yes visualstudio2017-workload-office
:: "Microsoft.VisualStudio.Workload.NetCrossPlat", 
chocolatey install -yes visualstudio2017-workload-netcrossplat
:: "Microsoft.VisualStudio.Workload.VisualStudioExtension", 
chocolatey install -yes visualstudio2017-workload-visualstudioextension
:: "Microsoft.VisualStudio.Workload.NativeCrossPlat", 
chocolatey install -yes visualstudio2017-workload-nativecrossplat
:: "Microsoft.VisualStudio.Workload.NetCoreTools", 
chocolatey install -yes visualstudio2017-workload-netcoretools

Visual Studio 2017 related Packages I still need to research from [WayBack] GitHub – jberezanski/ChocolateyPackages: Chocolatey packages maintained by me:

–jeroen

Read the rest of this entry »

Posted in .NET, Development, Software Development, Visual Studio 2017, Visual Studio and tools | Leave a Comment »

Delphi compile time assertions

Posted by jpluimers on 2021/02/24

My post on Delphi intrinsic functions that evaluate to consts as a step up to Delphi compile time assertions.

This is a corner case of Delphi language use, which can come in very handy when your code is changed in the future, and you want to be prepared to ensure that some changes do not violate some predefined boundaries.

Hopefully a future post will elaborate a bit more on actual usage, but for now, lets first show some examples, then some other languages that have a richer set of compile time assertions.

My original goal was to see if I could come up with a mechanism that allowed for better validation of generic types because Delphi generic constraints – still – are quite limited: Delphi Constraints in Generics – RAD Studio XE documentation wiki, so limiting or verifying the aspects of the concrete type often cannot be done by constraints.

C# had a similar limitation for constraining to enum, which finally got added some 13 years after adding generics, in 2018: [WayBack] Unmanaged, delegate and enum type constraints – C# 7.3 in Rider and ReSharper – .NET Tools Blog.NET Tools Blog.

Let’s start simple:

const
  // forbidden const values to check compile time assert:
  A = 0;
  B = 1;
  C = -1;
  // The below expressions all each generate a "[dcc32 Error] E2098 Division by zero" (so multiple errors in one compile)
  // Asserting at compile time using boolean expressions:
  BooleanAssertAIsNotZero =  1 div Ord(A <> 0);
  BooleanAssertBIsNotOne = 1 div Ord(B <> 1);
  // Asserting at compile time using numeric expressions:
  AssertAIsNotZero = 1 div A;
  AssertBIsNotOne =  1 div (B - 1);
  AssertBIsNotAbsOne =  1 div (Abs(B) - 1);
  AssertCIsNotAbsOne =  1 div (Abs(C) - 1);

This is all centered around generating a compile time error "[dcc32 Error] E2098 Division by zero", of which multiple can occur in one compile go (after compilation, the cursor focus will be at the first error) and which has been in the language for a very long time [WayBack] E2098: Division by zero.

The conversion of Boolean to Integer is done using Ord, a very powerful compile time intrinsic that evaluates to a constant.

You can use this for other intrinsics as well, for example:

type
  TDigits = 0..9;

const
  DigitsAreInteger = GetTypeKind(TDigits) = tkInteger;
  DigitsAreIntegerIsTrue = 1 div Ord(DigitsAreInteger);
  DigitsAreEnumeration = GetTypeKind(TDigits) = tkEnumeration; // compiles fine
  DigitsAreEnumerationIsTrue = 1 div Ord(DigitsAreEnumeration); // [dcc32 Error] E2098 Division by zero

The above learns that integer subranges are not enumerations, but stay integers.

You can now extend this to check longer boolean expressions, for instance to check if a record size matches certain criteria. For this we create records having zero to four bytes in size (yes, you can have empty record in Delphi, it in fact the only data structure that can be zero bytes in length, though the documentation [WayBack] Structured Types: record types does not state this is in fact possible ), then validate the sizes:

type
  TRecord0 = record
  end;

  TRecord1 = packed record
    FByte0: Byte;
  end;

  TRecord2 = packed record
    FByte0: Byte;
    FByte1: Byte;
  end;

  TRecord3 = packed record
    FByte0: Byte;
    FByte1: Byte;
    FByte2: Byte;
  end;

  TRecord4 = packed record
    FByte0: Byte;
    FByte1: Byte;
    FByte2: Byte;
    FByte3: Byte;
  end;

const
  AssertTRecord0SizeOf0 = 1 div Ord(SizeOf(TRecord0) = 0); // When expression is false: [dcc32 Error] E2098 Division by zero
  AssertTRecord0SizeOf1 = 1 div Ord(SizeOf(TRecord1) = 1); // When expression is false: [dcc32 Error] E2098 Division by zero
  AssertTRecord0SizeOf2 = 1 div Ord(SizeOf(TRecord2) = 2); // When expression is false: [dcc32 Error] E2098 Division by zero
  AssertTRecord0SizeOf3 = 1 div Ord(SizeOf(TRecord3) = 3); // When expression is false: [dcc32 Error] E2098 Division by zero
  AssertTRecord0SizeOf4 = 1 div Ord(SizeOf(TRecord4) = 4); // When expression is false: [dcc32 Error] E2098 Division by zero
  AssertTRecord0SizeOfMultipleOf4 = 1 div Ord(SizeOf(TRecord0) mod 4 = 0); // When expression is false: [dcc32 Error] E2098 Division by zero
  AssertTRecord4SizeOfMultipleOf4 = 1 div Ord(SizeOf(TRecord4) mod 4 = 0); // When expression is false: [dcc32 Error] E2098 Division by zero
  AssertTRecord0SizeOfMultipleOf4AndGreaterThan0 = 1 div Ord((SizeOf(TRecord0) mod 4 = 0) and (SizeOf(TRecord0) > 0)); // When expression is false: [dcc32 Error] E2098 Division by zero
  AssertTRecord4SizeOfMultipleOf4AndGreaterThan0 = 1 div Ord((SizeOf(TRecord4) mod 4 = 0) and (SizeOf(TRecord4) > 0)); // When expression is false: [dcc32 Error] E2098 Division by zero

That’s how far I got in my first experiments using this mechanism. Hopefully it gave you some inspiration too, so I welcome any usages you made with it.

Inline use of intrinsics can lead to no generated code at all

Since Delphi has no macro language, you cannot create your own intrinsic functions that evaluate to const. You could use a pre-processor though, as described in [WayBack] How to write Delphi compile-time functions – Stack Overflow.

The answer by Johan there however mentions clever use of in-line functions that do not generate any code at all (so effectively evaluate to a const). More on that in a future post.

Compile time assertions in other languages

Many languages support a form of [WayBack] Compile-time calculation – Rosetta Code. If such a language can errors out on compiling such a calculation, then you can have compile time assertions.

Compile time assertions are very much used in C and C++, where they are often called static assertions. Often they depend on macros, but C11 (C standard revision 11) has it built-in.

Since I also do quite a bit of .NET: [WayBack] Can C# Provide a static_assert? – Stack Overflow

Some links on how they work in C and C++, and what you can do with them:

–jeroen

Posted in .NET, C, C#, C++, Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

Nick Craver on Twitter: “1. “Are you ready to work on the auth code?” 2. New dev: “Hell yeah, bring it on!” 3.… “

Posted by jpluimers on 2021/01/28

[WayBack] Nick Craver on Twitter: “1. “Are you ready to work on the auth code?” 2. New dev: “Hell yeah, bring it on!” 3.… “.

Relevant because security often is a nightmare:

 

Both threads are a good read.

–jeroen

Read the rest of this entry »

Posted in .NET, Android, Development, Fun, Mobile Development, Software Development, Xamarin Studio | Leave a Comment »

NDC 2019 Keynote: Welcome to the Machine – Hadi Hariri – YouTube

Posted by jpluimers on 2021/01/27

I am really glad this keynote got recorded. Still very relevant, it is as much about software development as it is about society.

Go watch it, as it gives you reason to think about your role in the software development process, and in the information fire hose at large.

Back in the days, David Intersimone was right when he created the regular blog post “Sip from the Firehose” (for early materials, see [WayBack] GetPublished – Author Information: Firehose).

The talk main thread is about current and ever growing overload of information which basically makes it disinformation, combined with the abundance of “AI” recording devices around you that basically make you the product.

Basically we reached all the tick marks of these books:

The session is not just about “how bad is the situation” (it is very), but also provides directions on how to get out of it for both people in the development process, as well as consumers, producers and sharers of information.

via:

–jeroen

Read the rest of this entry »

Posted in .NET, Development, Opinions, Power User, Security, Software Development | Leave a Comment »

Run your unit tests in parallel with NUnit

Posted by jpluimers on 2021/01/26

TL;DR

The examples in this post are specific for NUnit but, you can apply this pattern for safely running unit tests in parallel to any unit test framework that supports parallel execution.

To safely run tests in parallel, do the following:

  1. Mark your test fixtures with the Parallelizable attribute and set the parallel scope to ParallelScope.All.
  2. Create a private class called TestScope and implement IDisposable.
  3. Put all startup and clean-up logic inside the TestScope constructor and .Dispose() method respectively.
  4. Wrap your test code in a using (var scope = new TestScope) { ... } block

From [WayBack] Run your unit tests in parallel with NUnit, which also covers:

  • Background (on why you might want this)
  • How to safely run tests in parallel
  • Maximizing parallel execution with Visual Studio
  • Maximizing parallel execution with Azure DevOps

Via: [WayBack] Sander Aernouts on Twitter: “Run unit tests in parallel with NUnit without having one test interfere with another test. https://t.co/FC0fNocGov”

–jeroen

Posted in .NET, Development, Software Development | Leave a Comment »

GitHub – drewnoakes/string-theory: Identify and reduce memory used by duplicate .NET strings

Posted by jpluimers on 2021/01/19

[WayBack] GitHub – drewnoakes/string-theory: Identify and reduce memory used by duplicate .NET strings:

Identifies opportunities to improve heap memory consumption by strings.

Finds duplicate strings and provides ways to see what object graphs are keeping them alive.

Once you identify a suspicious referrer, you can query to see what other strings it is holding across the whole heap, and the total number of wasted bytes.

Cool tool to help trim down .NET string memory usage.

Via: [WayBack] drewnoakes on Twitter: “This week I published #StringTheory, a tool for analysing and reducing the memory used by strings on the managed .NET heap. We are using it to improve @VisualStudio performance, with encouraging results so far. Try it on your apps!”

–jeroen

Posted in .NET, Development, Software Development | Leave a Comment »

How To Write Unmaintainable Code: Ensure a job for life ;-) by Roedy Green Canadian Mind Products

Posted by jpluimers on 2020/12/09

A great reference on how not to code still is

How To Write Unmaintainable Code

Ensure a job for life ;-)

Roedy Green Canadian Mind Products

I am still amazed when browsing through code, how many people use one or more of the anti-patterns in it.

One example I came across was this piece of Delphi RTL code:

class function TMarshalUnmarshalBase.ComposeKey(clazz: TClass; Field: string): string;
begin
  if clazz <> nil then
    Result := clazz.UnitName + SEP_DOT + clazz.ClassName + SEP_DOT + Field
  else
    Result := '';
end;

So I did a quick search at in the Delphi RTL for clazz, then found these occurences, indicating not only the authors of them have been under a rock, but also the code reviewers:

  • 98 in data\dbx\Data.DBXJSONReflect.pas
  • 7 in data\dbx\Data.DBXTransport.pas
  • 97 in data\rest\REST.JsonReflect.pas
  • 3 in DUnit\src\TestFramework.pas
  • 22 in indy\abstraction\IPPeerAPI.pas

I have seen similar things in many environments, even run-time libraries of others, though this is one of the worst examples and falls under the anti-pattern:

Thesaurus Surrogatisation

To break the boredom, use a thesaurus to look up as much alternate vocabulary as possible to refer to the same action, e.g. displayshowpresent. Vaguely hint there is some subtle difference, where none exists. However, if there are two similar functions that have a crucial difference, always use the same word in describing both functions (e.g. print to mean “write to a file”, “put ink on paper” and “display on the screen”). Under no circumstances, succumb to demands to write a glossary with the special purpose project vocabulary unambiguously defined. Doing so would be an unprofessional breach of the structured design principle of information hiding.

There is a great other anti-pattern in the document too:

Delphi/Pascal Only

: Don’t use functions and procedures. Use the label/goto statements then jump around a lot inside your code using this. It’ll drive ’em mad trying to trace through this. Another idea, is just to use this for the hang of it and scramble your code up jumping to and fro in some haphazard fashion.

Enjoy reading the anti-pattern descriptions, which are now maintained at [WayBack] GitHub – Droogans/unmaintainable-code: A more maintainable, easier to share version of the infamous http://mindprod.com/jgloss/unmain.html, as it was originally a multi-page hard to maintain set of small articles:

A lot of comments were posted because of it: [WayBack] Responses to Roedy’s Unmaintainable Code Essay

Via:

–jeroen

Posted in .NET, Delphi, Development, Software Development | 1 Comment »

.NET: interfaces that inherit from multiple base interfaces

Posted by jpluimers on 2020/12/03

For my link archive:

Read the rest of this entry »

Posted in .NET, C#, Delphi, Development, Software Development | Leave a Comment »

Delphi spring collections

Posted by jpluimers on 2020/12/02

[WayBack] Spring Collections I have a list of elements, there are, for example, 100 of them. List : IList; I want to get 5 values greater than 10 and … – Jacek Laskowski – Google+

Q

I have a list of elements, there are, for example, 100 of them.

List : IList<Integer>;

I want to get 5 values greater than 10 and I do it like this:

result: = List.Where(ValueIsGreatThan10).Take(5);

Will the “work loop” be executed a minimum number of times and if, for example, the first 5 values in the list will be greater than 5, then only the five will be checked? Or maybe the Where() loop will scan 100 elements, and Take() will return the first 5 results?

A (by Stefan Glienke)

Where and Take are streaming operators and only execute as much as required.

Also the operations have deferred execution. So your statement does not materialize any collection yet. Only if you iterate it will.

They are designed after the operators in .NET so the table from [WayBack] Classification of Standard Query Operators by Manner of Execution (C#) | Microsoft Docs applies. If you find any difference please report it.

Example:

var
  nums: IEnumerable<Integer>;
  i: Integer;
begin
  nums := TEnumerable.Range(1, 100).Where(
    function(const i: Integer): Boolean
    begin
      Writeln('checking: ', i);
      Result := i > 10;
    end
  ).Take(5);
  Writeln('query created');
  for i in nums do
    Writeln('got number: ', i);
end.

This code will print:

query created
checking: 1
checking: 2
checking: 3
checking: 4
checking: 5
checking: 6
checking: 7
checking: 8
checking: 9
checking: 10
checking: 11
got number: 11
checking: 12
got number: 12
checking: 13
got number: 13
checking: 14
got number: 14
checking: 15
got number: 15

–jeroen

Posted in .NET, Delphi, Development, Software Development | Leave a Comment »

FeaturesShim: using ShimGen for creating a shim to a program either console or GUI so you need only one bin directory

Posted by jpluimers on 2020/11/17

[WayBack] FeaturesShim is a cool Chocolatey feature that uses ShimGen.

This allows Chocolatey to take only one directory in your search PATH, with a lot of small files, that link to the much larger actual executable files.

ShimGen (like many other parts of Windows and some other parts of Chocolatey) is not open source, but the mechanism is documented.

More information:

–jeroen

Posted in .NET, Development, Power User, Software Development, Windows, Windows Development | Leave a Comment »