Generic Functions

Introduction

Imagine you want to pass different types of values to various functions to primarily accomplish the same purpose. You may be tempted to overload a function in various versions as follows:

public record Exercise
{
    // Use an integer as parameter
    void Show(int value)
    {
    }

    // Use a double-precision value as parameter
    void Show(double value)
    {
    }

    // Use a character as parameter
    void Show(char value)
    {
    }
}

You can then call the functions. Here are examples:

using static System.Console;

public class Exercise
{
    // Use an integer as parameter
    static void Show(int value)
    {
        WriteLine("Natural Number: " + value.ToString());
    }

    // Use a double-precision value as parameter
    static void Show(double value)
    {
        WriteLine($"Floating - Point Number: {value}");
    }

    // Use a character as parameter
    static void Show(char value)
    {
        WriteLine(string.Format("Character: {0}", value));
    }

    public static int Main()
    {
        Title = "Generic Examples";

        // Call the function that takes an integer as argument
        Show(246);

        // Call the version of the function that takes a character as argument
        Show('G');

        // Call the version of the function that takes a decimal as argument
        Show(355.65);

        return 1_001;
    }
}

This would produce:

Natural Number: 246
Character: G
Floating - Point Number: 355.65

Press any key to close this window . . .

We passed a constant value directly to the method when we called it. Remember that you can also first declare a variable, assign it a value, and then pass that variable to the method. Here are examples:

using static System.Console;

public class Exercise
{
    // Use an integer as parameter
    static void Show(int value)
    {
        WriteLine("Natural Number: " + value.ToString());
    }

    // Use a double-precision value as parameter
    static void Show(double value)
    {
        WriteLine($"Floating - Point Number: {value}");
    }

    // Use a character as parameter
    static void Show(char value)
    {
        WriteLine(string.Format("Character: {0}", value));
    }

    public static int Main()
    {
        Title = "Generic Examples";
        
        int value1 = 246;
        char value2 = 'G';
        double value3 = 355.65;

        // Call the function that takes an integer as argument
        Show(value1);

        // Call the version of the function that takes a character as argument
        Show(value2);

        // Call the version of the function that takes a decimal as argument
        Show(value3);

        return 1_002;
    }
}

Although this is based on the concept of function overloading, another way you can solve this type of problem is to create one function that "doesn't know" the type of value that would be passed to it but the function is equipped to process the value somehow. Based on the above code, you can create one function that takes an argument and uses its value. To do this, at the time you are defining the function, you only let the function know that it would receive an argument but you don't specify the type of value that it will process. Such a function is referred to as generic.

Creating a Generic Function

A generic function is a function that can process a value whose type is known only when the value is accessed. To create a generic function, on the right side of the name of the function, type the <> operator. Inside the <> operator, enter a letter or a name, which is referred to as parameter type. Here is an example:

void Show<TypeOfValue>()
{
}

One of the ways you can use the parameter type is to pass an argument to the function. You do this by preceding the name of the argument with the parameter type. Here is an example:

void Show<TypeOfValue>(TypeOfValue value)
{
}

In the body of the function, you can process the argument as you see fit. At a minimum, and based on our earlier code, you can simply convert it to a string. Here is an example:

void Show<TypeOfValue>(TypeOfValue value)
{
    return value.ToString();
}

By tradition, most programmers and most documents use the letter T for the parameter type. Here is an example:

public void Show<T>(T value)
{
	return value.ToString();
}

Calling a Generic Function

As mentioned earlier, one of the particularities of a generic function is that, at the time it is defined, the function doesn't know the type of the parameter. This means that, when calling the function, you must make sure you clearly specify the type of value that will be processed. You can do this by directly passing (a constant of) the type of value that the function will process. Here are different examples of calling our Show() function:

using static System.Console;

void Show<T>(T value)
{
    WriteLine(string.Format("Value: {0}", value.ToString()));
}

Title = "Generic Examples";
        
int value1 = 246;
char value2 = 'G';
double value3 = 355.65;

// Call the function that takes an integer as argument
Show(value1);

// Call the version of the function that takes a character as argument
Show(value2);

// Call the version of the function that takes a decimal as argument
Show(value3);

As an alternative, when calling the function, you can type the name of the function, followed by angle brackets. Inside the brackets, enter the data type of the value that will be processed. After the angle brackets, open the parentheses and, inside of them, type the constant value that will be processed. Here are examples:

using static System.Console;

void Show<T>(T value)
{
    WriteLine(string.Format("Value: {0}", value.ToString()));
}

Title = "Generic Examples";
        
int value1 = 246;
char value2 = 'G';
double value3 = 355.65;

// Call the function that takes an integer as argument
Show<int>(value1);

// Call the version of the function that takes a character as argument
Show<char>(value2);

// Call the version of the function that takes a decimal as argument
Show<double>(value3);

Returning a Value from a Generic Function

We already know that you can create an overloaded function where each version takes a different type of parameter. Here are examples from our earlier introduction:

using static System.Console;

public class Exercise
{
    // Use an integer as parameter
    static string Show(int value)
    {
        return value.ToString();
    }

    // Use a double-precision value as parameter
    static string Show(double value)
    {
        return value.ToString();
    }

    // Use a character as parameter
    static string Show(char value)
    {
        return value.ToString();
    }

    public static int Main()
    {
        Title = "Generic Examples";

        // Call the function that takes an integer as argument
        WriteLine("Natural Number: " + Show(246));

        // Call the version of the function that takes a character as argument
        WriteLine(string.Format("Character: {0}", Show('G')));

        // Call the version of the function that takes a decimal as argument
        WriteLine($"Floating - Point Number: {Show(355.65)}");

        return 1_005;
    }
}

In the same way, when creating a generic function, you can make it return a value of your choice and call the function when necessary. Here is an example:

using static System.Console;

string Show<T>(T value)
{
    return value.ToString();
}

Title = "Generic Examples";

// Call the function that takes an integer as argument
WriteLine("Natural Number: " + Show(246));

// Call the version of the function that takes a character as argument
WriteLine(string.Format("Character: {0}", Show('G')));

// Call the version of the function that takes a decimal as argument
WriteLine($"Floating - Point Number: {Show(355.65)}");

Remember that, when calling the function, you can include the type of the generic value. Here are examples:

using static System.Console;

string Show<T>(T value)
{
    return value.ToString();
}

Title = "Generic Examples";

// Call the function that takes an integer as argument
WriteLine("Natural Number: " + Show<int>(246));

// Call the version of the function that takes a character as argument
WriteLine(string.Format("Character: {0}", Show<char>('G')));

// Call the version of the function that takes a decimal as argument
WriteLine($"Floating - Point Number: {Show<double>(355.65)}");

A Generic Function With Various Parameters

Introduction

Just like a function can take one argument, it can use various generic parameters. You can pass one parameter as a known type and the other as a generic type. Here is an example:

string Show<T>(string msg, T value)
{
    return $"{msg}, {value}";
}

When calling the function, make sure you pass the desired but appropriate argument for each call. Here are examples:

using static System.Console;

void Show<T>(string msg, T value)
{
    WriteLine($"{msg}: {value}");
}

Title = "Generic Examples";

int value1 = 5_268;
char value2 = 't';
double value3 = 7_294_570.71539;

// Call the version that takes an integer as argument
Show<int>("Integer", value1);

// Call the version that takes a character as argument
Show<char>("Character", value2);

// Call the version that takes a decimal number as argument
Show<double>("Decimal", value3);

This would produce:

Integer: 5268
Character: t
Decimal: 7294570.71539

Press any key to close this window . . .

Although we directly passed the values to the function when calling it, you can first declare a variable before passing it to the function. Here are examples:

using static System.Console;

void Show<T>(string msg, T value)
{
    WriteLine($"{msg}: {value}");
}

Title = "Generic Examples";

const int iValue = 5_268;
var message = "Integer";
Show(message, iValue);

message = "Character";
const char cValue = 't';
Show(message, cValue);

message = "Decimal";
const double dValue = 7_294_570.71539;
Show(message, dValue);

A Generic Function With Various Parameter Types

As seen above, you can pass different arguments to a function. You can also pass different types of parameters, in any appropriate order of your choice, to a method. To pass two parameter types to a function, inside its <> operator, enter the names of two parameter types separated by a comma. Here is an example:

void Show<FirstType, SecondType>()
{

}

If you want to use the parameter types, you can pass an argument for each to the function. Remember that each parameter type represents a data type; so you can use it as the type of an argument. Here are examples:

void Show<FirstType, SecondType>(FirstType first,
                                            SecondType second)
{

}

In the body of the function, you can then use the arguments as you see fit. For example, you can involve them in one or more expressions. Here is an example:

string Show<FirstType, SecondType>(FirstType first,
                                              SecondType second)
{
    return $"First: {first}, Second: {second}";
}

By tradition, habit or simplicity, when a generic function uses two parameter types, the first type is named U and the second type is named V. Here is an example:

string Show<U, V>(U first, V second)
{
    return $"First: {first}, Second: {second}";
}

When a generic function uses three parameter types, the first type can be named U, the second type can be named V, and the third type van be named W.

Calling a Generic Function With Various Parameter Types

To call a function that takes various parameters, you can simply pass the value of each argument as we have done so far. You can also pass the names of variables. Here are examples:

using static System.Console;

void Show<U, V>(U first, V second)
{
    WriteLine($"First: {first}; Second: {second}");
}

Title = "Generic Examples";

const int iValue = 9;
var message = "Integer";
Show(message, iValue);

message = "Character";
const char cValue = '@';
Show(message, cValue);

message = "Decimal";
const double dValue = 827_838_575.694683;
Show(message, dValue);

This would produce:

First: Integer; Second: 9
First: Character; Second: @
First: Decimal; Second: 827838575.694683

Press any key to close this window . . .

An alternative is to specify the type of each argument. To do this, inside the <> operator on the right side of the name of the function, enter the data types separated by a comma. The arguments can be of the same type or different types. It is up to you to determine the type of a particular argument when calling the function. Here are examples:

using static System.Console;

void Show<U, V>(U first, V second)
{
    WriteLine($"First: {first}; Second: {second}");
}

Title = "Generic Examples";

const int iValue = 9;
var message = "Integer";
Show<string, int>(message, iValue);

message = "Character";
const char cValue = '@';
Show<string, char>(message, cValue);

message = "Decimal";
const double dValue = 827_838_575.694683;
Show<string, double>(message, dValue);

Generic Functions and Optional Arguments

One of the arguments of a generic function can be a parameter type while the other is a known type. Consider this example:

string Show<T>(string msg, T value)
{
    return $"{msg}, {value}";
}

void Create()
{
    var number = Show<int>("Integer", 246);
    dynamic character = Show<char>("Character", 'G');
    var floating = Show<double>("Decimal", 355.65);
}

If you want to assign default values to arguments, only the known data type(s) can receive optional arguments. There is no default value for the parameter type because its type is not known. Consider the following function:

string Show<T>(string msg = "Number", T value = null)
{
    return $"{msg}, {value}";
}

void Create()
{
    var number = Show<int>("Integer", 246);
    dynamic character = Show<char>("Character", 'G');
    var floating = Show<double>("Decimal", 355.65);
}

This would produce the following error:

Error	1	A value of type '<null>' cannot be used as a default parameter 
because there are no standard conversions to type 'T'	
C:\Users\Administrator\AppData\Local\Temporary Projects\exo1\Exercise.cs
	5	58	GenericInheritance

As a result, if you are creating a function that takes more than one argument and you want to use default values, the parameter type(s) must come first and the one (those) with optional value(s) must come last. The parameter type(s) must not have default value(s). Consider the following code:

string Show<T>(T value, string msg = "Number")
{
    return $"{msg}, {value}";
}

void Create()
{
    var number = Show<int>(246);
    dynamic character = Show<char>('G', "Character");
    var floating = Show<double>(355.65);
}

Generic Functions and Named Arguments

When calling a function that takes one or more arguments, you can use the name of an argument followed by a colon and followed by the desired value. This is also valid for parameter types. Here are examples:

using static System.Console;

string Evaluate<T>(T right, T left, char operation)
{
    return $"{left} {operation} {right}";
}

void Prepare()
{
    var a = 20.64;
    var b = 797.24;
    string strFirstResult = Evaluate<double>(a, b, '+');

    var r = "Research ";
    var d = " Development";
    var oper = '&';

    string strSecondResult = Evaluate<string>(operation: oper, right: d, left: r);

    string strThirdResult = Evaluate<int>(right: 14159, left: 31, operation: '.');
}

Title = "Generic Vaplues";
WriteLine("Generic Values");
WriteLine("------------------------------------");

var a = 20.64;
var b = 797.24;
string strResult = Evaluate<double>(a, b, '+');

WriteLine("Operation: {0}", strResult);

var r = "Research ";
var d = " Development";
var oper = '&';

strResult = Evaluate<string>(operation: oper, right: d, left: r);

WriteLine(string.Format("Expression: {0}", strResult));

strResult = Evaluate<int>(right: 14159, left: 31, operation: '.');

WriteLine($"Decimal Number: {strResult}");

WriteLine("=======================================");

This would produce:

Generic Values
------------------------------------
Operation: 797.24 + 20.64
Expression: Research  &  Development
Decimal Number: 31 . 14159
=======================================
Press any key to close this window . . .

Overloading a Generic Function

As we have seen in previous lessons, there are various ways you can overload a function, and generic functions bring new features. One version of a function can be a generic type while the other is not. In this case, even if the functions don't use any parameter, there would not be a name conflict. Here is an example:

public class Exercise
{
    void Create()
    {
    }

    void Create<T>()
    {
    }
}

You can have two functions that take the same types and numbers of arguments. In order to avoid name conflict, one of the functions can (must) be generic. Here is an example:

public class Exercise
{
    void Create(string msg)
    {
    }

    void Create<T>(string msg)
    {
    }

    string Show<T>(string msg, int value)
    {
    }

    string Show<FirstType, SecondType>(string msg, int value)
    {
    }
}

Finally, you can have functions that use different types and/or numbers of arguments. Here is an example:

public class Exercise
{
    string Show<T>(string msg, T value)
    {
       	return $"{msg}, {value}";
    }

    string Show<FirstType, SecondType>(FirstType first,
                                              SecondType second)
    {
       	return $"First:  {first}, Second: {second}";
    }
}

Generic Classes

Generic Types and Methods

As a reminder, in our lessons, a function is an action that is created in the document that contains the Main(string[] args) function (especially for a console application).

Everything we learned so far about generic functions is directly applicable to the methods of a class, as generic methods. For example, we had learned to create generic functions. In the same way, we can create a generic function as a member of a class, making it a generic method. Here is an example:

namespace IntroductoryGenerics
{
    public class Generator
    {
        public void Show<T>(T value)
        {
        }
    }
}

The main difference between what we call a function and a method is that, to use a method outside the class, you must declare a variable of the class and then call the method. Here are examples:

using static System.Console;

Title = "Generic Vaplues";
WriteLine("Generic Values");
WriteLine("----------------");

int value1 = 246;
char value2 = 'G';
double value3 = 355.65;
Generator gen = new Generator();

// Call the version that takes an integer as argument
gen.Show(value1);

// Call the version that takes a character as argument
gen.Show(value2);

// Call the version that takes a decimal number as argument
gen.Show(value3);

WriteLine("=================================");

namespace IntroductoryGenerics
{
    public class Generator
    {
        public void Show<T>(T value)
        {
            WriteLine(string.Format("Value: {0}", value.ToString()), "Generic Examples");
        }
    }
}

Introduction to Creating a Generic Class

Like a function, a class can be created as a generic one. When a class is created as generic, it is asked to process a value without knowing what type that value is. This means that the class will know the type of value only when its object is accessed.

To create a generic class, on the right side of the name of the class, type the <> operator and enter a name for the parameter type. Here is an example:

public class Generator<TypeOfValue>
{
}

This parameter type is just a representative of a data type. As a data type, you can use it to declare a variable in the body of the class. Here is an example:

public class Generator<TypeOfValue>
{
    public TypeOfValue value;
}

After declaring such a variable, you can use it in your project. For example, you can access it outside the class using the period operator. Inside the class, one way you can use the variable is to involve it in an expression in one of the methods of the class. Here is an example:

public class Generator<TypeOfValue>
{
    public TypeOfValue Value;

    public string Show()
    {
        return Value.ToString();
    }
}

Using a Generic Class

After creating a generic class, you can use it. One way to do this, as we have learned in previous lessons, consists of declaring a variable for it. In previous lessons, to declare a variable of a class, we would write:

SomeClass sc = new SomeClass();

If the class is generic, on the right side of its name when declaring the variable, type the <> operator. Inside this operator, enter the data type that will be processed as the parameter type of the generic class. Here is an example:

Generator<int> gen = new Generator<int>();

You can also declare a variable of a generic type using the var or the dynamic keyword. To do this, use var or dynamic on the left side of the variable name, omit the <> operator and the data type. Here are examples:

Generator<int> gen = new Generator<int>();

var calculation = new Generator<int>();
dynamic expression = new Generator<int>();

After declaring the variable (whether using the name of the class or the var or the dynamic keyword), you can then access the member(s) of the class using the period operator. Here are examples:

using static System.Console;

Title = "Generic Vaplues";
WriteLine("Generic Values");
WriteLine("------------------------------------");

Generator<int> gen = new Generator<int>();
var calculation = new Generator<char>();
dynamic expression = new Generator<double>();

WriteLine("A Value: {0}", gen.Value);
WriteLine(string.Format("A Calculation: {0}", calculation.Value));
WriteLine($"An Expression: {expression.Value}");
            
WriteLine("=======================================");
            
namespace IntroductoryGenerics
{
    public class Generator<TypeOfValue>
    {
        public TypeOfValue Value;

        public string Show()
        {
            return Value.ToString();
        }
    }
}

This would produce:

Generic Values
------------------------------------
A Value: 0
A Calculation:
An Expression: 0
=======================================
Press any key to close this window . . .

Passing a Parameter Type to a Method

We saw that you could declare a variable of a parameter type in a generic class. Another way you can use it is to pass it as an argument to a method and make the argument a parameter type. As seen previously, you can use the argument as you see fit. For example, you can display its value to the user. Here is an example:

using static System.Console;

Title = "Generic Vaplues";
WriteLine("Generic Values");
WriteLine("----------------");

var iValue = 246;
Generator<int> gen = new Generator<int>();

gen.Show(iValue);
            
char cValue = 'G';
var calculation = new Generator<char>();
calculation.Show(cValue);

double nbr = 355.65;
dynamic expression = new Generator<double>();
expression.Show(nbr);
            
WriteLine("=================================");
            
namespace IntroductoryGenerics
{
    public class Generator<TypeOfValue>
    {
        public void Show(TypeOfValue value)
        {
            WriteLine("Value: {0}", value);
        }
    }
}

This would produce:

Generic Values
----------------
Value: 246
Value: G
Value: 355.65
=================================
Press any key to close this window . . .

In the same way, you can pass the parameter type to a constructor of the class. Here is an example:

public class Generator<T>
{
    public T Value;

    public Generator(T value)
    {
        
    }
}

Since the generic parameter and the parameter of the constructor are the same type, you can involve them in the same expression, such as assigning one to the other. Here is an example:

public class Generator<T>
{
    public T Value;

    public Generator(T value)
    {
        Value = value;
    }
}

Returning a Parameter Type

Besides, or as opposed to, passing a parameter type, in the class, you can create a method that returns a parameter type. Once again, you can primarily observe the rules we reviewed for returning a value from a function. Here is an example:

public class Generator<T>
{
    public T Value;

    public Generator(T value)
    {
        this.Value = value;
    }

    private T Create()
    {
        return this.Value;
    }
}

A Property of a Parameter Type

You can create a property that is of the parameter type of the generic class. There is no significant rule to follow when creating the property, except that you should remember that, at the time you are creating the property, the class "doesn't know" the type of the parameter. Here is an example:

public class Generator<T>
{
    public T val;

    public Generator(T value)
    {
        val = value;
    }

    public T Value
    {
        get { return val; }
        set { val = value; }
    }
}

Options on Generic Classes

A Generic Class with Multiple Type Parameters

As done for generic functions, when creating a generic class, you can specify more than one parameter type. To do this, in the <> operator, after the first generic type, enter a comma and another generic type. Here is an example:

public class Generator<FirstType, SecondType>
{
}

Once again, remember that, to make the parameter types simple to read, you can name them U, V, etc.

If you know for sure that the parameters will be of the same type, you can use one method to process both. Otherwise, you can declare the necessary members for each type. You can also create a method that would take many arguments with each argument of a particular type. Here are examples:

public class Generator<U, V>
{
    private U t;
    private V v;

    public void SetTValue(U value)
    {
        t = value;
    }

    public U GetTValue()
    {
        return t;
    }

    public void SetVValue(V value)
    {
        v = value;
    }
    public V GetVValue()
    {
        return v;
    }

    public string Show(U tValue, V vValue)
    {
        return $"{tValue}{vValue}";
    }
}

When declaring a variable for the class, make sure you appropriately specify the list of parameter types. Here are two examples:

using static System.Console;

Title = "Generic Vaplues";
WriteLine("Generic Values");
WriteLine("----------------");

Generator<int, int> yearlySalary = new Generator<int, int>();
yearlySalary.SetTValue(84);
yearlySalary.SetVValue(680);
string strNumber = yearlySalary.Show(yearlySalary.GetTValue(), yearlySalary.GetVValue());

WriteLine("Yearly Salary: {0}", strNumber);
            
Generator<char, double> price = new Generator<char, double>();
price.SetTValue('$');
price.SetVValue(185.45);
string strValues = price.Show(price.GetTValue(), price.GetVValue());

WriteLine(string.Format("Item Price: {0}", strValues));
            
Generator<short, decimal>  disparate = new Generator<short, decimal>();
disparate.SetTValue(425);
disparate.SetVValue(.35m);
strNumber = disparate.Show(disparate.GetTValue(), disparate.GetVValue());

WriteLine($"Some Number: {strNumber}");
            
Generator<int, string> company = new Generator<int, string>();
company.SetTValue(1800);
company.SetVValue("flowerslovers.com");
strNumber = company.Show(company.GetTValue(), company.GetVValue());

WriteLine($"Web Site: {strNumber}");

WriteLine("=================================");
            
namespace IntroductoryGenerics
{
    public class Generator<U, V>
    {
        private U t;
        private V v;

        public void SetTValue(U value)
        {
            t = value;
        }

        public U GetTValue()
        {
            return t;
        }

        public void SetVValue(V value)
        {
            v = value;
        }
        public V GetVValue()
        {
            return v;
        }

        public string Show(U tValue, V vValue)
        {
            return $"{tValue}{vValue}";
        }
    }
}

This would produce:

Generic Values
----------------
Yearly Salary: 84680
Item Price: $185.45
Some Number: 4250.35
Web Site: 1800flowers.com
=================================
Press any key to close this window . . .

You can also declare the variable using the var or the dynamic keyword. To do this, on the left side of the assignment operator, type only the var or the dynamic keyword and the name of the variable. Here is an example:

using static System.Console;

Title = "Generic Vaplues";
WriteLine("Generic Values");
WriteLine("--------------------------------");

Generator<int, int> yearlySalary = new Generator<int, int>();
yearlySalary.SetTValue(84);
yearlySalary.SetVValue(680);
string strNumber = yearlySalary.Show(yearlySalary.GetTValue(), yearlySalary.GetVValue());

WriteLine("Yearly Salary: {0}", strNumber);
            
Generator<char, double> price = new Generator<char, double>();
price.SetTValue('$');
price.SetVValue(185.45);
string strValues = price.Show(price.GetTValue(), price.GetVValue());

WriteLine(string.Format("Item Price: {0}", strValues));
            
var disparate = new Generator<short, decimal>();
disparate.SetTValue(425);
disparate.SetVValue(.35m);
strNumber = disparate.Show(disparate.GetTValue(), disparate.GetVValue());

WriteLine($"Some Number: {strNumber}");
            
dynamic company = new Generator<int, string>();
company.SetTValue(1800);
company.SetVValue("flowers.com");
strNumber = company.Show(company.GetTValue(), company.GetVValue());

WriteLine($"Web Site: {strNumber}");

WriteLine("=================================");
            
namespace IntroductoryGenerics
{
    public class Generator<U, V>
    {
        private U t;
        private V v;

        public void SetTValue(U value) => t = value;
        public U GetTValue() => t;
        public void SetVValue(V value) => v = value;
        public V GetVValue() => v;
        public string Show(U tValue, V vValue) => $"{tValue}{vValue}";
    }
}

If a generic class has more than one parameter type, they don't have to be of the same type. At the time you are creating the class, you may not specify their types but you can anticipate that they would be different. It is when you declare the variable that you would need to determine their precise types.

Even if the parameters are of primitive types, you can first declare the variables and pass them to the class.

A Class as a Parameter Type

So far, in our examples, we treated the parameter type as a primitive data type. A parameter type can also be a formal class, either one that you created yourself or one that exists in any available library, including the .NET library. When creating the generic class, you must follow all the rules we have reviewed so far for generic classess. Here is such a simple class:

public class Generator
{
    public string Show(TypeOfValue val)
    {
        return $"{val}";
    }
}

As mentioned already, the class that would be processed by the generic class must have been previously created so it can be used as a parameter. Here is an example:

public class FourSideGeometricFigure
{
    public string? Name  { get; set; }
    public double Base   { get; set; }
    public double Height { get; set; }
    
    public double Area
    {
        get { return Base * Height; }
    }

    public override string ToString()
    {
        return $"Type:  {Name}, Base: {Base}, Height: {Height}, Area: {Area}";
    }
}

public class Generator<T>
{
    public string Show(T val)
    {
        return val.ToString();
    }
}

When declaring a variable of the generic class, make sure you enter the name of the normal class in place of the parameter type. You can declare the variable using its name or using the var or the dynamic keyword. Here are examples:

using static System.Console;

Title = "Generic Vaplues";
WriteLine("Generic Values");
WriteLine("--------------------------------");

FourSideGeometricFigure sqr = new FourSideGeometricFigure();
sqr.Name = "Square";
sqr.Base = 36.82;
sqr.Height = 36.82;
Generator<FourSideGeometricFigure> exoSquare =
                    new Generator<FourSideGeometricFigure>();

WriteLine("Shape Summary\n\t{0}", exoSquare.Show(sqr));
WriteLine("--------------------------------");

var rect = new FourSideGeometricFigure();
rect.Name = "Rectangle";
rect.Base = 52.94;
rect.Height = 27.58;

dynamic exoRect = new Generator<FourSideGeometricFigure>();

WriteLine(string.Format("hape Summary\n\t{0}", exoRect.Show(rect)));

WriteLine("=================================");

namespace IntroductoryGenerics
{
    public class FourSideGeometricFigure
    {
        public string? Name  { get; set; }
        public double Base   { get; set; }
        public double Height { get; set; }
        
        public double Area
        {
            get { return Base * Height; }
        }

        public override string ToString()
        {
            return $"Type:  {Name}\n\tBase: {Base}\n\tHeight: {Height}\n\tArea: {Area}";
        }
    }

    public class Generator<T>
    {
        public string Show(T val)
        {
            return val.ToString();
        }
    }
}

This would produce:

Generic Values
--------------------------------
Shape Summary
        Type:  Square
        Base: 36.82
        Height: 36.82
        Area: 1355.7124
--------------------------------
hape Summary
        Type:  Rectangle
        Base: 52.94
        Height: 27.58
        Area: 1460.0852
=================================
Press any key to close this window . . .

Previous Copyright © 2008-2024, FunctionX Saturday 19 March 2022 Next