Choose a generic implementation if the type parameter is a structure or class

I would like to implement my common IQueue<T> interface in an efficient way by doing one implementation if T is a structure and another if T is a class.

 interface IQueue<T> { ... } class StructQueue<T> : IQueue<T> where T : struct { ... } class RefQueue<T> : IQueue<T> where T : class { ... } 

I would like to have a factory method that based on T kind returns an instance of one or the other:

 static IQueue<T> CreateQueue<T>() { if (typeof(T).IsValueType) { return new StructQueue<T>(); } return new RefQueue<T>(); } 

Of course, the compiler indicates that T should be a type argument with a null / null value.

Is there a way to pass T to a structure type (and to a class) to compile the method? Is it possible to dispatch runtime using C #?

+5
source share
2 answers

You can use Reflection to do this as follows:

 static IQueue<T> CreateQueue<T>() { if (typeof(T).IsValueType) { return (IQueue<T>)Activator .CreateInstance(typeof(StructQueue<>).MakeGenericType(typeof(T))); } return (IQueue<T>)Activator .CreateInstance(typeof(RefQueue<>).MakeGenericType(typeof(T))); } 

This code uses the Activator.CreateInstance method to create queues at runtime. This method accepts the type of object you want to create.

To create a Type that represents a generic class, this code uses the MakeGenericType method to create a closed generic Type object from public generic types, such as StructQueue<> .

+5
source

Yacoub Massad's answer is correct, but with a little change, you do not need to run MakeGenericType for every CreateQueue call.

The following code runs MakeGenericType once for each type, because for each type QueueFactory<T> there is a separate static variable, QueueFactory<int>.queueType will get StructQueue<int> , and QueueFactory<string>.queueType will get RefQueue<int>

 public class QueueFactory<T> { static Type queueType = typeof(T).IsValueType ? typeof(StructQueue<>).MakeGenericType(typeof(T)) : typeof(RefQueue<>).MakeGenericType(typeof(T)); public static IQueue<T> CreateQueue() { return (IQueue<T>)Activator.CreateInstance(queueType); } } 

In my semi-scientific test, he created 1 million copies in about a tenth of the time.

+1
source

Source: https://habr.com/ru/post/1238894/


All Articles