Georgi Tonchev
Georgi Tonchev

Reputation: 35

Invoking a generic interface's method through reflection invokes a method from a base implementation of the same interface in Unity

I have the following generic interface:

public interface IGenericInterface<T>
{
    public void PrintGenericParameterTypeName()
    {
        Debug.Log($"Generic parameter type: {typeof(T).Name}");
    }
}

I then have the following classes:

public class Base : MonoBehaviour, IGenericInterface<int>
{
}
public class Derived : Base, IGenericInterface<string>
{
}

I have an instance of type Derived in my scene. When I run this code, I correctly get both of its generic interfaces (IGenericInterface<string> and IGenericInterface<int>)

var derived = FindObjectOfType<Derived>();

var derivedType = derived.GetType();

var derivedTypeGenericInterfaces =
    derivedType.GetInterfaces()
    .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IGenericInterface<>));

However, when invoking the PrintGenericParameterTypeName method for each of the interfaces, both times the method from the base class's interface implementation is invoked (IGenericInterface<int>).

foreach (var genericInterface in derivedTypeGenericInterfaces)
{
    var printMethod = genericInterface.GetMethod("PrintGenericParameterTypeName");
    printMethod?.Invoke(derived, null);
}

Recreating this in a console application (the only difference being the Base class does not inherit from anything) works as expected and the method is once invoked for IGenericInterface<string> and once for IGenericInterface<int>. In Unity, however, both times the method is invoked for IGenericInterface<int>. Any ideas?

EDIT:

Changing the default interface method's return type to its generic type T seems to have fixed the problem.

public T PrintGenericParameterTypeName()
{
    Debug.Log($"Generic parameter type: {typeof(T).Name}");
    return default;
}

And I am now getting the expected results. But I still have no explanation for this unexpected behavior.

Upvotes: 0

Views: 89

Answers (1)

user3259797
user3259797

Reputation:

Try moving the implementation out of interface to the base class. Something like this...

public interface IGenericInterface<T>
{
    abstract void PrintGenericParameterTypeName();
    
}
public class Base : IGenericInterface<int>
{
    public void PrintGenericParameterTypeName()
    {
        Console.Write($"Generic parameter type: {typeof(T).Name}");
    }
}

public class Derived : Base, IGenericInterface<string>
{
}

Then call it like this...

    foreach (var i in derivedTypeGenericInterfaces)
{
    i.InvokeMember("PrintGenericParameterTypeName",
        BindingFlags.DeclaredOnly |
        BindingFlags.Public |
        BindingFlags.Instance | BindingFlags.InvokeMethod, null,  derived, new object[] {});
}

Upvotes: 1

Related Questions