5

I need to create instance of a generic class like this:

 Type T = Type.GetType(className).GetMethod(functionName).ReturnType;
 var comparer = new MyComparer<T>(); // ERROR: "The type or namespace name 'T' could not be found"

I found this answer where this is possible only with reflection. But using reflection I get object which I need to cast to my generic type. I tried like this

 Type myGeneric = typeof(MyComparer<>);
 Type constructedClass = myGeneric.MakeGenericType();
 object created = Activator.CreateInstance(constructedClass);
 var comparer = (T)Convert.ChangeType(created, T);// ERROR: "The type or namespace name 'T' could not be found"

but get the same error. How to solve it?

Here is a complete example:

    public static bool Test(string className, string functionName, object[] parameters, object correctResult)
    {
        var method = Type.GetType(className).GetMethod(functionName);
        Type T = method.ReturnType;
        var myResult = method.Invoke(null, parameters);
        dynamic myResultAsT = Convert.ChangeType(myResult, T);
        dynamic correctResultAsT = Convert.ChangeType(correctResult, T);
        var comparer = new MyComparer<T>();    // Problem is here!!!       
        return comparer.Equals(myResultAsT, correctResultAsT);            
    }

The idea is to make a unit test which will call a function with parameters and compare its result with the correct result. But I need custom comparer, so I implement MyComparer which I cannot use because of a compiler error.

public class MyComparer<T> : IEqualityComparer<T>
{
    public bool Equals(T x, T y){/* some implementation*/}
}
7
  • Your error messages don't make sense, are you sure that's what they say? Commented May 10, 2017 at 17:55
  • @DavidG Full compiler error is: The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?). Why it doesn't make sense? Commented May 10, 2017 at 17:58
  • 1
    Then you are not showing enough code, please show a minimal reproducible example Commented May 10, 2017 at 17:59
  • First, there's no such thing as a "template" in C#. There are only generics. Second, as you've already seen, there are adequate answers describing how to instantiate a generic type based on a type known only at run-time. Third, as most people find when they think they need this, they still run into problems trying to use the dynamically instantiate object, because the code still needs to know at compile-time the type. Commented May 10, 2017 at 21:11
  • You seem to actually have several different problems; we need you to provide a good minimal reproducible example that shows clearly what the one problem at the moment is. Consider making this your highest-level problem, i.e. the question about the unit-testing, because it seems likely you are really having an XY Problem moment here. I'd be surprised if dynamically instantiating your object is needed at all. Commented May 10, 2017 at 21:11

2 Answers 2

8

I found very simple solution to problem. There is no need to cast object to specific type T, just use dynamic keyword instead of casting

   Type myGeneric = typeof(MyComparer<>);
   Type constructedClass = myGeneric.MakeGenericType(T);
   object created = Activator.CreateInstance(constructedClass);
   dynamic comparer = created; // No need to cast created object to T

and then I can use comparer normally to call its methods like:

   return comparer.Equals(myResultAsT, correctResultAsT);

According to LueTm comments, it is probably possible to use reflection again and call comparer methods, but this solution looks much easier.

Sign up to request clarification or add additional context in comments.

3 Comments

This is definetly the nicer solution.
@Dejan where is this (T) coming from? "MakeGenericType(T);" I don't see it in your code snippet.
@metabuddy Please read the first code snippet (1st line) from the question. T is return type of some method in my case, but can be any Type.
2

Looks like you're almost there:

// t is a variable, so make it lowercase. This is where some of the confusion comes from
Type t = Type.GetType(className).GetMethod(functionName).ReturnType;
Type myGeneric = typeof(IEqualityComparer<>);

// You need to provide the generic type to make it generic with
// You want IEqualityComparer<T>, so:
Type constructedClass = myGeneric.MakeGenericType(t); 

// Now create the object
object created = Activator.CreateInstance(constructedClass);

// This is tricky without more context...
// You could try this, but to tell you more I would need to know where you use
// the comparer instance. Are you using it in a LINQ query, or in a Sort()?
// If so just cast it to a IEqualityComparer<YourType>, and
// make YourType whaterver you need it to be in the list or the query...
var comparer = (IEqualityComparer<object>)created;

4 Comments

Now, it is compiling, but it throws InvalidCastException in runtime. Unable to cast object of type 'MyComparer1[System.Double]' to type 'MyComparer1[System.Object]'. I use MyComparer insted of IEqualityComparer.
I am using comparer instance only for Equals with two objects. I am not using it in a LINQ query. I write the usage of comparer in edited question.
Just make the call to the Equals method with reflection as well, and it will work. Just write if you need assistance and I will edit the answer.
There is no need for reflection and casting, I found very simple solution: dynamic comparer = created; then call Equals from comparer and it will compile and work.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.