What does “where T : class, new()” mean?

Let’s start with a piece of code;

void Add<T>(T item) where T : class, new();

It’s called a ‘constraint’ on the generic parameter T. It means that T must be a reference type (a class) and that it must have a public default constructor.

That means T can’t be an int, float, double, DateTime or any other struct (value type). It could be a string, or any other custom reference type, as long as it has a default or parameter-less constructor.

For understanding we can break it into two parts;

where T : class

Means that the type T must be a reference type (not a value type).

where T : new()

Means that the type T must have a parameter-less constructor. Having this constraint will allow you to do something like T field = new T(); in your code which you wouldn’t be able to do otherwise.

We then combine the two using a comma to get:

where T : class, new()

Just to clarify, if you don’t have the class clause as part of the where T…, then it is safe to use int, float, double etc

Here is an example;

struct MyStruct { } // structs are value types

class MyClass1 { } // no constructors defined, so the class implicitly has a parameter less one

class MyClass2 // parameter less constructor explicitly defined
{
    public MyClass2() { }
}

class MyClass3 // only non-parameter less constructor defined
{
    public MyClass3(object parameter) { }
}

class MyClass4 // both parameter less & non-parameter less constructors defined
{
    public MyClass4() { }
    public MyClass4(object parameter) { }
}

interface INewable<T>
    where T : new()
{
}

interface INewableReference<T>
    where T : class, new()
{
}

class Checks
{
    INewable<int> cn1; // ALLOWED: has parameter less ctor
    INewable<string> n2; // NOT ALLOWED: no parameter less ctor
    INewable<MyStruct> n3; // ALLOWED: has parameter less ctor
    INewable<MyClass1> n4; // ALLOWED: has parameter less ctor
    INewable<MyClass2> n5; // ALLOWED: has parameter less ctor
    INewable<MyClass3> n6; // NOT ALLOWED: no parameter less ctor
    INewable<MyClass4> n7; // ALLOWED: has parameter less ctor

    INewableReference<int> nr1; // NOT ALLOWED: not a reference type
    INewableReference<string> nr2; // NOT ALLOWED: no parameter less ctor
    INewableReference<MyStruct> nr3; // NOT ALLOWED: not a reference type
    INewableReference<MyClass1> nr4; // ALLOWED: has parameter less ctor
    INewableReference<MyClass2> nr5; // ALLOWED: has parameter less ctor
    INewableReference<MyClass3> nr6; // NOT ALLOWED: no parameter less ctor
    INewableReference<MyClass4> nr7; // ALLOWED: has parameter less ctor
}

Resources

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

https://stackoverflow.com/questions/4737970/what-does-where-t-class-new-mean

Reflection – What are the benefits

Generally, when people talk about reflection, the main concern is the performance. Because it runs on runtime, so theoretically, it is a little bit slower than the normal application. But it is flexible for many scenarios, especially if you develop the framework. If it is acceptable to spend a few seconds (or only hundreds of milliseconds) to load assemblies, then feel free to use it.

Let’s walk through an example; We are going to use an interface called “ISpeaker”.

internal interface ISpeaker
{
    string SayHello();
}

Create three implementation classes:

English Speakers

internal class EnglishSpeaker : ISpeaker
{
    public string Name => this.GetType().ToString();
    public string SayHello()
    {
        return "Hello!";
    }
}

Urdu Speakers

internal class UrduSpeaker : ISpeaker
{
    public string Name => this.GetType().ToString();
    public string SayHello()
    {
        return "as-salaam-alaikum";
    }
}

Chinese Speakers

internal class ChineseSpeaker : ISpeaker
{
    public string Name => this.GetType().ToString();
    public string SayHello()
    {
        return "Nihao";
    }
}

Now we can use reflection to find all the implementations of ISpeaker interface and call their methods or properties.

internal class ReflectionHelper
{
    public static List<Type> GetAvailableSpeakers()
    {
        // You can also use AppDomain.CurrentDomain.GetAssemblies() to load all assemblies in the current domain.
        // Get the specified assembly.
        var assembly =
                Assembly.LoadFrom(Path.Combine(Directory.GetCurrentDirectory(), "ReflectionDemo.dll"));
        // Find all the types in the assembly.
        var types = assembly.GetTypes();
        // Apply the filter to find the implementations of ISayHello interface.
        var result = types.Where(x => x.IsClass && typeof(ISpeaker).IsAssignableFrom(x)).ToList();
        // Or you can use types.Where(x => x.IsClass && x.GetInterfaces().Contains(typeof(ISpeaker))).ToList();
        return result;
    }
}

In this class, we load the specified dll file that contains types we need. Then we can apply the LINQ query to find all the implementations of ISpeaker interface using Reflection.

Test the program output. we can output the name and call SayHello method of each speaker:

using ReflectionDemo;
using System.Reflection;

Console.WriteLine("Hello, World!");

Console.WriteLine("Here is the Reflection sample:");
// Find all the speakers in the current domain
var availableSpeakers = ReflectionHelper.GetAvailableSpeakers();
foreach (var availableSpeaker in availableSpeakers)
{
    // Create the instance of the type
    var speaker = Activator.CreateInstance(availableSpeaker);
    // Get the property info of the given property name
    PropertyInfo namePropertyInfo = availableSpeaker.GetProperty("Name");
    // Then you can get the value of the property
    var name = namePropertyInfo?.GetValue(speaker)?.ToString();
    Console.WriteLine($"I am {name}");
    // Invoke the method of the instance
    Console.WriteLine(availableSpeaker.InvokeMember("SayHello", BindingFlags.InvokeMethod, null, speaker, null));
}
Console.WriteLine();
Console.ReadKey();

Run the program, you will see the below output:

If we need to add other speakers in other languages, just add the implementation classes in the same project. .NET reflection can automatically find out all the required classes and call the methods correctly.

It is extremely useful when we create the plugin-type applications. First we make the interfaces and call the methods from the client by reflection. Then we can create plugins following the interface for the client, which can be loaded as the *.dll files dynamically and executed.

Another scenario is for the framework development. As a framework developer, you will not be able to know what implementations the users will create, so you can only use reflection to create these instances. One example is in some MVVM frameworks, if you create the classes following the conventions, eg. xxxViewModel, the framework can find all the ViewModels and load them automatically using reflection.

The main namespaces we need to use for reflection are System.Reflection and System.Type. You may also need to know the below terms:

Resources

Reflection in .NET

Viewing Type Information

Dynamically Loading and Using Types

https://levelup.gitconnected.com/four-ways-to-generate-code-in-c-including-source-generators-in-net-5-9e6817db425

https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support

Return multiple values to a method caller

This is a code sample for returning multiple values from a c# method. For example, imagine a method that accepts multiple parameters and return two parameters;

So far the best method that I have found is this;

public Tuple<int, int> GetMultipleValue()
{
     return Tuple.Create(1,2);
}

This works in .NET 4 and up. Tuples with two values have Item1 and Item2 as properties.

Here is a list of different methods;

1. ref / out parameters

using ref:

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    int add = 0;
    int multiply = 0;
    Add_Multiply(a, b, ref add, ref multiply);
    Console.WriteLine(add);
    Console.WriteLine(multiply);
}

private static void Add_Multiply(int a, int b, ref int add, ref int multiply)
{
    add = a + b;
    multiply = a * b;
}

using out:

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    int add;
    int multiply;
    Add_Multiply(a, b, out add, out multiply);
    Console.WriteLine(add);
    Console.WriteLine(multiply);
}

private static void Add_Multiply(int a, int b, out int add, out int multiply)
{
    add = a + b;
    multiply = a * b;
}

2. struct / class

struct Result
{
    public int add;
    public int multiply;
}
static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.add);
    Console.WriteLine(result.multiply);
}

private static Result Add_Multiply(int a, int b)
{
    var result = new Result
    {
        add = a * b,
        multiply = a + b
    };
    return result;
}

using class:

class Result
{
    public int add;
    public int multiply;
}
static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.add);
    Console.WriteLine(result.multiply);
}

private static Result Add_Multiply(int a, int b)
{
    var result = new Result
    {
        add = a * b,
        multiply = a + b
    };
    return result;
}

3. Tuple

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    var result = Add_Multiply(a, b);
    Console.WriteLine(result.Item1);
    Console.WriteLine(result.Item2);
}

private static Tuple<int, int> Add_Multiply(int a, int b)
{
    var tuple = new Tuple<int, int>(a + b, a * b);
    return tuple;
}

C# 7 Tuples

static void Main(string[] args)
{
    int a = 10;
    int b = 20;
    (int a_plus_b, int a_mult_b) = Add_Multiply(a, b);
    Console.WriteLine(a_plus_b);
    Console.WriteLine(a_mult_b);
}

private static (int a_plus_b, int a_mult_b) Add_Multiply(int a, int b)
{
    return(a + b, a * b);
}

C# 7 Tuples More..

(string, string, string) LookupName(long id) // tuple return type
{
    ... // retrieve first, middle and last from data storage
    return (first, middle, last); // tuple literal
}

which could then be used like this:

var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");

You can also provide names to your elements (so they are not “Item1”, “Item2” etc). You can do it by adding a name to the signature or the return methods:

(string first, string middle, string last) LookupName(long id) // tuple elements have names

or

return (first: first, middle: middle, last: last); // named tuple elements in a literal

They can also be deconstructed, which is a pretty nice new feature:

(string first, string middle, string last) = LookupName(id1); // deconstructing declaration

Resource

https://stackoverflow.com/questions/748062/return-multiple-values-to-a-method-caller

Convert a Console App to Class Library

The big difference, you can run a console app but you can’t run a class library. Usually, Console App has Program.cs file and will compile to .exe file, a class library by default is not executable and will compile to a .dll. In .NET Core console app can also compile to DLL.

A Console App has a flow and can be executed. A Class Library is just a collection of functions that you call from another source. Class libraries by themselves are pretty useless without something to call the functions inside them.

Console App has a static MAIN method that’s an entry point. When deciding to make a method or Static class, I always keep this in mind.

A static class can be used as a convenient container for sets of methods that just operate on input parameters and do not have to get or set any internal instance fields.

Create console app. Add a greeting method. Run the app. Switch the output type to Class Libarary. Right-Click on Project -> Properties;

Before;

After;

You have best of the both worlds.

How to load assembly in SSIS script task that isn’t in the GAC

The documented and recommended way to reference a custom assembly from an SSIS Script Task or Script Component is to install it in the Global Assembly Cache (GAC).  However this is not always possible or simple to do.

Here’s a simple workaround for loading an assembly from an arbitrary location.  The idea is to register an AppDomain.AssemblyResolve event handler.

The .NET Framework provides the AppDomain.AssemblyResolve event for applications that require greater control over assembly loading. By handling this event, your application can load an assembly into the load context from outside the normal probing paths, select which of several assembly versions to load, emit a dynamic assembly and return it, and so on. This topic provides guidance for handling the AssemblyResolve event.

Resolving Assembly Loads

Which does just what we need.  The question is where and how to wire it up.  The trick is to realize that .NET’s Just-in-Time (JIT) compilation is responsible for loading dependent assemblies, and therefore guarantees that the assemblies referenced in a type’s method won’t be loaded until just before the method is executed.  This means that in the type’s static constructor we can reliably wire up the AssemblyResolve event that will supply the referenced types.

When you create a SSIS Script Task or Script Component SSIS generates a class for you called ScriptMain, and you can wire-up the event in a Static Constructor for that type.  A Static Constructor is guaranteed to be called exactly once “before the first instance is created or any static members are referenced.”, so therefore before the dependent assemblies are loaded.

[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
     static ScriptMain()
     {
         AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
     }
     static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
     {
         if (args.Name.Contains("ssisHelper"))
         {
             string path = @"c:\temp\";
             return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "ssisHelper.dll"));
         }
         return null;
     }
    . . .

You can then drop the referenced assemblies in a well-known location on the SSIS server, or use a package variable to refer to the location and pass that in to the Script Task or Script Component.

If you are having issues with getting the dll path from a variable, Here is the work around. Basically you need to remove the “static” qualifier from the constructor and the event handler declarations and just make them public. So: public static ScriptMain() becomes public ScriptMain() and public static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) becomes public Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args).

Here is the modified version;

[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
	public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
  //the assemblyl is not registered in GAC and referenced from a folder.
  public ScriptMain()
  {
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyReference);
  }

  public System.Reflection.Assembly CurrentDomain_AssemblyReference(object sender, ResolveEventArgs args)
  {
   //string path = @"C:\Dev\PathToSSISHelper\";
   string path = Dts.Variables["User::PathToSSISHelper"].Value.ToString();
   if (args.Name.Contains("SSISHelper"))
   {
      return System.Reflection.Assembly.LoadFrom(System.IO.Path.Combine(path, "SSISHelper.dll"));
   }
   return null;
  }
  //end of reflection
.....

}

If you try to read the assemblies from a network share, you might get (System.NotSupportedException). Therefore replaced the LoadFile(path) with the UnsafeLoadFrom(path) call as workaround. Please use it only for your own or other wellknown assemblies, not downloaded assemblies from unknown authors, because this would be a security issue.

Here is the working code, the referenced DLL is “System.Web.Helpers.dll” and the network share path gets configured in the user variable “LibPath” (VS 2015,SQL Server 2017):

public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string path = Variables.LibPath.ToString();

    if (args.Name.Contains("System.Web.Helpers"))
    {
        return System.Reflection.Assembly.UnsafeLoadFrom(System.IO.Path.Combine(path, "System.Web.Helpers.dll"));
    }

    return null;
}

/// <summary>
/// This method is called once, before rows begin to be processed in the data flow.
/// </summary>
public override void PreExecute()
{
    base.PreExecute();

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

Resource

Load custom assembly in SSIS

https://docs.microsoft.com/en-us/archive/blogs/dbrowne/how-to-load-an-assembly-in-a-ssis-script-task-that-isnt-in-the-gac