Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The type T must be a reference type in order to use it as parameter while using interface

I got the error for the below code

public static Moq.Mock<T> CreateInstanceOfIMock<T>() {
    return new Moq.Mock<T>();
}

I have solved the error it by using referred class type. See this below code

public static Moq.Mock<T> CreateInstanceOfIMock<T>() where T : class
{
    return new Moq.Mock<T>();
}

Now I want to move this var mockColorsRepository = new Moq.Mock<IColorsRepository>(); code into common code by using generics. here IColorsRepository is an interface. So I made an interface reference for T instead of class like this below code

public static Moq.Mock<T> CreateInstanceOfIMock<T>() where T : interface
{
    return new Moq.Mock<T>();
}

But am getting The type T must be a reference type in order to use it as parameter error. How can I refer interface instead of class to T. How can I achieve this?

like image 507
Ramesh Rajendran Avatar asked Nov 30 '17 06:11

Ramesh Rajendran


People also ask

What is the purpose of an interface constraints on a type parameter?

Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.

What is a type parameter in C#?

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 of the generic type.

Where is generic type constraint?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.

Which of the following generic constraints restricts the generic type parameter to an Object of the class?

Value type constraint If we declare the generic class using the following code then we will get a compile-time error if we try to substitute a reference type for the type parameter.


2 Answers

class and struct in generic type constaints do not mean the same thing as the class and struct declarations that are used to declare class or struct types. Instead, they only restrict whether a generic type argument is a reference type (class), or a value type (struct).

So when you do where T : class you are not saying that T needs to be a class, you are saying that T needs to be a reference type. Similarly struct for value types.

Interfaces on their own do not have this property, so an interface can be implemented by both a reference type and a value type. As such, restricting your type to be of an interface does not really make sense there.

In your case, Moq requires you to pass a reference type, so you need to transitively carry over that type constraint in all your helper methods:

public static Moq.Mock<T> CreateInstanceOfIMock<T>()
    where T : class
{
    return new Moq.Mock<T>();
}

That’s all you need to do to create a mock of any valid type. You can use it with an interface using CreateInstanceOfIMock<IColorsRepository>() or any other type.

Of course, at that point, the method does not really make that much sense since it does not give you any benefit over just instantiating the mock yourself.

like image 199
poke Avatar answered Oct 16 '22 22:10

poke


There's no generic constraint in C# to enforce that a type argument is an interface. But where T : class is really "where T is a reference type" - it includes interfaces.

If you wanted to enforce that T is an interface rather than a class, you could perform an execution-time check using typeof(T) within the method, but in this case it sounds like you don't really need to constrain it to be an interface.

I'm not sure that the "helper" method is particularly useful though - if you compare:

var mock = Helper.CreateInstanceOfIMock<Foo>();

and

var mock = new Moq.Mock<Foo>();

or even (unless you have Mock<T> as another type somewhere) just a using Moq; directive and

var mock = new Mock<T>();

The latter seems just as readable and shorter... it makes sense if you're going to add more logic in your method, but if it's only ever going to call the constructor, I don't think I'd bother with it.

like image 33
Jon Skeet Avatar answered Oct 16 '22 21:10

Jon Skeet