How to store a generic function in a variable in c#?

c# generic method where t multiple types
generic method in c#
generics in c# with real time example
c# generic method multiple types
c# generic return type and parameter
c# generic method return different type
c# generics
c# generic method return type

I have the following code:

public interface IMenuItem
{
    IWebElement Parent { get; }
}

public class MenuItems
{
    public T GetMenuItem<T>() where T : IMenuItem, new()
    {
        var menuItem = new T();

        return menuItem;
    }
}

public abstract class Page : IEnumerable<IComponent>
{
    private Func<IMenuItem> _getMenuItems = new MenuItems().GetMenuItem<IMenuItem>;
}

I'm trying to store the new MenuItems().GetMenuItem<IMenuItem> function in _getMenuItems field, but since this is a generic function this isn't working. How can I store generic functions into a variable?

Doing new MenuItems().GetMenuItem<IMenuItem> won't work and it tells me:

'IMenuItem' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'MenuItems.GetMenuItem()'

Now I have many concrete types that implement IMenuItem I want the delegate to accept those. I don't want to make a seperate delegate for every concrete type that implements IMenuItem. Rather I have a single delegate that can accept concrete types that implement IMenuItem.

The problem is with the new() constraint.

The new constraint specifies that a type argument in a generic class declaration must have a public parameterless constructor. To use the new constraint, the type cannot be abstract.

Since IMenuItem is an interface, it cannot be instantiated, and therefore the new() constraint will be a problem.

Edit:

You can solve this in a couple of ways:

  1. You can use reflection for retrieving the method and invoking it:

    var method = typeof(MenuItems).GetMethod("GetMenuItem");
    var instance = new MenuItems(); // Maybe convert the class into a static class??
    var genericMethod = method.MakeGenericMethod(typeof(MenuItem1));
    var result = genericMethod.Invoke(instance, null) as IMenuItem;
    
  2. Use dynamic to invoke it:

    dynamic instance = new MenuItems(); // Maybe convert the class into a static class??
    var result = instance.GetMenuItem<MenuItem1>() as IMenuItem;
    
  3. Hold an instance of MenuItems instead of the method itself:

    var menuItems = new MenuItems();
    var result = _instance.GetMenuItem<MenuItem1>() as IMenuItem;
    

Generics in C, A generic class can be defined using angle brackets <>. is a simple generic class with a generic member variable, generic method and property. Example: Generic class. class MyGenericClass<T> { private T genericMemberVariable; public� C# Variables. A variable is a name given to a storage area that is used to store values of various data types. Each variable in C# needs to have a specific type, which determines the size and layout of the variable's memory. For example, a variable can be of the type String, which means that it will be used to store a string value.

I don't think a field is appropriate here. The best you can do is a wrapper method:

public abstract class Page : IEnumerable<IComponent>
{
    private static readonly MenuItems menuItems = new MenuItems();        

    protected Func<T> GetMenuItems<T>() where T : IMenuItem, new()
    {
        return () => menuItems.GetMenuItem<T>();
    }

}

Generics In C, C# Generics are used to create generic collections in C#. convert a value type to a reference type by storing the variable into System. The Add() method is responsible for adding any type of objects into the collection and� Generics in C#. Generics introduced in C# 2.0. It allows you to define a class with placeholders for the type of its fields, methods, parameters, etc. Generics replace these placeholders with some specific type at compile time. A generic class can be defined using angle brackets <>.

In your MenuItems class, new means

That is a constraint on the generic parameter T. It must be a class (reference type) and must have a public parameter-less default constructor.

That means T can't be an int, float, double, DateTime or any other struct (value type).

Source: https://stackoverflow.com/a/4737985/1349365

So what you can do with your current structure is :

public interface IMenuItem
{
    IWebElement Parent { get; }
}

public class MenuItem : IMenuItem
{
    public IWebElement Parent => throw new NotImplementedException();
}

public class MenuItems
{
    public T GetMenuItem<T>() where T : IMenuItem, new()
    {
        var menuItem = new T();

        return menuItem;
    }
}
public abstract class Page : IEnumerable<IComponent>
{
    private Func<IMenuItem> _getMenuItems = new MenuItems().GetMenuItem<MenuItem>;
}

As your error says, you need a concrete class to pass into GetMenuItem method.

[PDF] Generic Programming in C, Using void * and function pointers to write generic code. ▷ Using libraries C allows a function call to have a variable number of that will be stored in our list. The point about generic types, is that although you may not know them at "coding time", the compiler needs to be able to resolve them at compile time. Why? Because under the hood, the compiler will go away and create a new type (sometimes called a closed generic type) for each different usage of the "open" generic type.

Generic Type Parameters, In a generic type or method definition, a type parameter is a placeholder for a specific type that a client specifies when they create an instance� Now, given you have a variable bar defined as such: var bar = typeof(Bar); You then want to be able to call Foo<T>, replacing T with your instance variable bar. Here's how: // Get the generic method `Foo` var fooMethod = typeof(Qaz).GetMethod("Foo"); // Make the non-generic method via the `MakeGenericMethod` reflection call.

Func<T,TResult> Delegate, Encapsulates a method that has one parameter and returns a value of the type specified by the TResult parameter. C#; VB; C++; F# This example declares a Func<T,TResult> variable and assigns it a lambda expression that is declared as a Sub rather than as a Function ), use the generic Action<T> delegate instead. Generic methods can be overloaded on several type parameters. For example, the following methods can all be located in the same class: void DoWork() { } void DoWork<T>() { } void DoWork<T, U>() { } C# Language Specification. For more information, see the C# Language Specification. See also. System.Collections.Generic; C# Programming Guide

C# Generic Class, Generic Method Examples, Create and use generic classes and methods. See type parameter the Write method. test1.Write(); // Use the generic type Test with a string type parameter. The generic value variable is a type of variable with a wide range that can store any kind of data, including text, numbers, dates and arrays, and is particular to UiPath Studio. Generic value variables are automatically converted to other types, in order to perform certain actions.

Comments
  • Is your intent actually to create (and discard) a new MenuItems instance every time the delegate is invoked? That seems like a potential problem with the design. Either GetMenuItem should be static or the MenuItems instance should itself be created elsewhere.
  • That would work -- except, as others have noted, you do need to pass a concrete type to GetMenuItem, IMenuItem on its own won't do it. You may wish to instead leave it up to MenuItems to determine the type (by making it a MenuItems<T>, for example), or else you want to pass a Func<IMenuItem> to it rather than have a new() constraint, so it's up to callers to decide what to instantiate and how.
  • actually this is a good question, so did I understand you correctly that your would like to use this variable _getMenuItems like this: IMenuItem temp = _getMenuItems<MyTypeImplementingIMenuItem>() ? and you want this as a variable and not a method ?=! because a method would only be a wrapper for the new MenuItems().GetMenuItem<IMenuItem>() call ?=!
  • @MongZhu that's correct! I don't need a method wrapper I want to do this in a variable like you said: IMenuItem temp = _getMenuItems<MyTypeImplementingIMenuItem>()
  • I think you meant to write private Func<IMenuItem> _getMenuItems = () => menuItems.GetMenuItem<IMenuItem>();
  • I have many concrete classes that implement IMenuItem with the solution you gave I would need to create a delegate for every concrete class.
  • Then as @amir-popovich suggests var menuItems = new MenuItems(); var result = _instance.GetMenuItem<MenuItem1>() as IMenuItem; is best choice.