The benefits of using Arrays over Lists in C#

I’m an ardent proponent of using Arrays (T[]) over Lists (Lisf<T>) in C#. In my case, it’s mostly web services running in Azure and libraries, consumed by such services. In this blog post I’ll be collecting the pros and cons of using one over another.

First and foremost, the methodological argument. Types matter, whenever it’s a parameter type or a return type. There are many types but this one is mine. Type indicates the intend.

What’s the intend of a list? A list is a collection that allows an item to be added:


What means a list is not a final collection. Its “true name” is ArrayList. That it, the IList interface implemented by using an Array. Historically, C# design has copied so many things from Java but unfortunately this class name one was not one of them. Its core functionality pivots around automatic resizing (you can arbitrarily add and remove items) and capacity.

While an array is the opposite. It’s final. Once created, its size cannot be changed. Of course, you can resize it but that will be a new array with the content copied over. Like strings, arrays are immutable in that regards.

Side note: there are readonly lists and immutable arrays. There is a number of problems with them, starting with a too long name. How do you like Task<IReadOnlyCollection<OrderDetails>> comparing to just Task<OrderDetsils[]>? Because C# is notoriously “chatty” aka high ceremony.

As I said, I’m using C# to write web services in the cloud. What means it’s strings from a database sent over a network. The result of a query? Final. The results of a HTTP request? Final as well.

Then why would your Database-over-Network class return your a type whose intend is adding stuff into it??

interface IOrderService
    Task<List<OrderDetails>> GetOrders();

Obviously, it should be an array instead.

Here we could stop. In my mind this argument alone is enough to always use arras until you clearly need otherwise. But let’s discuss other, technical arguments supporting my position.

  1. What happens when you’re instantiating a generic List<T>? “The whole transitive closure of types, starting with that root type, will be compiled”. See Joe Duffy’s blog post on this topic. Generics are not bad but they’re relatively expensive.
  1. Accessing an item inside an array involves a bounds checking. Which are in many cases eliminated by JIT optimization down the road anyway. See this question on Stack Overflow and Matt Warren’s blog post.The code for array indexer is getting translated into IL directly:
IL_0014: ldelem.i4

While list indexer is a whole virtual method call:

IL_001b:  callvirt   instance !0 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)

To be continued…

Posted in Programming | Tagged | Leave a comment

How to set access policy on Key Vault in another subscription aka How to deploy to resource group in another subscription using ARM template?

The model for my Service Fabric infrastructure consists of two major parts:

  • Data Center (think Azure region)
  • Scale Unit (think Service Fabric cluster and its child resources)

But today due to the limitation around AAD first party application we decided to add one more level on top of it:

  • Global secrets (think 1PA token encryption/decryption certificate)

What means the Key Vault extension now needs to download yet another certificate from a global Key Vault. It will use User-Assigned Identity to authorize on this Key Vault. What means the Key Vault needs to have the appropriate access policies. But here’s the challenge:

  • Subscription 1
    • Resource Group 1 (Global Secrets)
      • Global Key Vault
  • Subscription 2
    • Resource Group 2 (DC)
      • Regional Key Vault
    • Resource Group 3 (SU)
      • Service Fabric cluster
      • VMSS
        • Key Vault extensions run here

What means the ARM template for UAID needs somehow set the access policy for in on a Key Vault not just in another resource group but in another subscription altogether. Here’s how to do that:

  "$schema": "",
  "contentVersion": "",
  "parameters": {
    "uaidName": {
      "type": "string"
    "globalSecretsSbscriptionId": {
      "type": "string"
    "globalSecretsKvName": {
      "type": "string"
  "variables": {
    "apiVersion": "2019-09-01",
    "idApiVersion": "2018-11-30",
    "kvApiVersion": "2019-09-01",
    "tenantId": "[subscription().tenantId]",
    "uaidRef": "[concat('Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('uaidName'))]"
  "resources": [
      "name": "[concat('KeyVault-Global-', parameters('uaidName'))]",
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "[variables('apiVersion')]",
      "subscriptionId": "[parameters('globalSecretsSbscriptionId')]",
      "resourceGroup": "[parameters('globalSecretsKvName')]",
      "properties": {
        "mode": "Incremental",
        "template": {
          "$schema": "",
          "contentVersion": "",
          "resources": [
              "type": "Microsoft.KeyVault/vaults/accessPolicies",
              "name": "[concat(parameters('globalSecretsKvName'), '/add')]",
              "apiVersion": "[variables('kvApiVersion')]",
              "properties": {
                "accessPolicies": [
                    "tenantId": "[variables('tenantId')]",
                    "objectId": "[reference(variables('uaidRef'), variables('idApiVersion')).principalId]",
                    "permissions": {
                      "keys": [
                      "secrets": [
                      "certificates": [

Posted in Programming | Tagged , | Leave a comment

How to split array into string for Service Fabric cluster ARM template

In order to use a certificates for Service Fabric cluster issues by custom, non publicly trusted CA you’d need to supply a list of thumbprints of intermediate CAs. In a form of a comma-separated string. What means if you have an array of thumbprints (what’s natural as it’s an easier way to maintain the list) like this:

"clusterCertIssuers": [
  "417E225037FBFAA4F95761D5AE729E1AEA7E3A42", // Microsoft IT TLS CA 1
  "54D9D20239080C32316ED9FF980A48988F4ADF2D", // Microsoft IT TLS CA 2
  "8A38755D0996823FE8FA3116A277CE446EAC4E99", // Microsoft IT TLS CA 4
  "AD898AC73DF333EB60AC1F5FC6C4B2219DDB79B7", // Microsoft IT TLS CA 5

Then you would need to convert them to a string like this:

"certificateCommonNames": {
  "commonNames": [
      "certificateCommonName": "[variables('clusterCertSubjectName')]",
      "certificateIssuerThumbprint": "417E225037FBFAA4F95761D5AE729E1AEA7E3A42,54D9D20239080C32316ED9FF980A48988F4ADF2D,8A38755D0996823FE8FA3116A277CE446EAC4E99,AD898AC73DF333EB60AC1F5FC6C4B2219DDB79B7"
  "x509StoreName": "[variables('certificateStoreName')]"

What obviously nobody wants to do. If only ARM supported a join(string, array)function! Here’s a UserVoice post dated back to May 2017. As of date of writing, there is no such string function whatsoever.

Here’s a solution, hopefully temporal, until ARM comes up with a proper one:

"clusterCertIssuersArr": {
  "copy": [
      "name": "certsLoop",
      "count": "[length(variables('clusterCertIssuers'))]",
      "input": "[concat(variables('clusterCertIssuers')[copyIndex('certsLoop')], ',')]"
"clusterCertIssuersStr": "[replace(replace(replace(string(variables('clusterCertIssuersArr').certsLoop), '[\"', ''), '\"]', ''), '\",\"', '')]",
"clusterCertIssuersSubstr": "[substring(variables('clusterCertIssuersStr'), 0, sub(length(variables('clusterCertIssuersStr')), 1))]",

It does 3 things:

  1. Creates a temporal array where each element of the initial array is appended by comma
  2. Converts the temporal array into a string and replaces all JSON array artifacts with empty string (effectively removes them), means ["a","b"] becomes just a,b
  3. Drop the last comma

That’s it, folks. Happy deployments!

Posted in Programming | Tagged , | Leave a comment

Carnation Anapa Winery, vol 2, day 33: topping up

Since the second carboy with Cabernet Sauvignon was lacking some volume to do proper anaerobic fermentation I needed to top it up. But unfortunately I couldn’t find any juice that’d match (grape, location, year) mine so I decided to add already finished wine.

I purchased 4 bottles of 2016 Nine Hats Cabernet Sauvignon made on Prosser, WA what’s close enough to Zillah, WA. But it turned out to be not enough, I need about 2 more, and I cannot find anymore around as apparently I bought out all local stock.

But actually I should’ve bought 1 or 2 magnums. I would save considerable amount of money and would add something more closely matching my wine by year.

Posted in Winemaking | Tagged | Leave a comment

Carnation Anapa Winery, vol 2, day and 30: oak chips

I’ve ordered a 1-pound bag of medium toasted French oak chips on Amazon and over the course of past two days added about 55g (~2oz) in each of the filled full carboys:

  • B#1 Syrah “wild”
  • B#2 Syrah “calm”
  • B#3 Cabernet Sauvignon “good boy”

I again don’t have enough juice to top up the last outstanding carboy, it’s about ¾ full:

  • B#4 Cabernet Sauvignon “bad boy”
Posted in Winemaking | Leave a comment

Carnation Anapa Winery, vol 2, day 22: Specific gravity

I’m measuring specific gravity in the buckets with Cabernet Sauvignon:

  • Bucket #4: 1.006
  • Bucket #5: 1.022
  • Bucket #6 “bad boy”: 1.080

I also measured the temperature inside the carboys:

  • Batch #1 “wild”: 60.09F
  • Batch #2 “calm”: 67.09F
Posted in Winemaking | Tagged | Leave a comment

Carnation Anapa Winery, vol 2, day 21: racking, specific gravity

I’m racking my Syrah and measure specific gravity in each of two 5-gallon carboys. Now on I’ll come them batches with specific name that describe their behavior.

  • Syrah Batch #1 “wild”: 0.992. I decided to keep in garage where it’s cooler since it’s already October.
  • Syrah Batch #2 “calm”: 0.993. This one I moved inside the house as an experiment to see the difference between temperatures.
Posted in Winemaking | Tagged | Leave a comment

Carnation Anapa Winery, vol 2, day 19: Cabernet Sauvignon (cont’d)

My weight: 78.50 kg

Bucket #6:

  • 27 kg

I got so much grapes this year that it took me 4 days to finish the destemming and crushing. The very last batch got contaminated with some sort of fungus or mold. So I added the double dosage of Potassium Metabisulfite, that it 2 x ¼ tsp per 5 gallons of must. I’ll keep the bucket opened in garage for 24 hours before adding yeast. Which I don’t have anymore anyway.

Total amount of Cabernet Sauvignon I got this year is 74.15 kg (163.47 lbs). What has filled full three 5-gallon buckets.

Posted in Winemaking | Tagged | Leave a comment

Carnation Anapa Winery, vol 2, day 17: Cabernet Sauvignon (cont’d)

My weight: 78.00 kg

Bucket #5:

  • 24.15 kg

Yeast: 1 pack of Lalvin Bourgovin RC 212

Posted in Winemaking | Tagged | Leave a comment

Carnation Anapa Winery, vol 2, day 16: Cabernet Sauvignon

I decided to do not delay and start processing the recently picked grapes today. So first weight it in.

Some precalculations:

  • My weight: 79.40 kg
  • With empty container: 80.85 kg
  • Empty container: 1.45 kg

Bucket #4:

  • 23.00 kg

Yeast: 1 pack of Lalvin Bourgovin RC 212.

Posted in Winemaking | Tagged | Leave a comment