6

I want to cast an object as an generic custom Interface.

This is my interface:

public interface IContainer<T>
{
    IEnumerable<T> SaveToCache(IEnumerable<T> models);
}

public class Container<T>
{
    IEnumerable<T> SaveToCache(IEnumerable<T> models);
}

I'm using this interface in a Serviceclass:

public class Manager()
{
    public Manager()
    {
        address = new Container<Address>(this);
        // more containers are constructed here...
    }

    private static Container<Address> address;
    public static Container<Address> Address => address;

    // here are more properties of Type Container<T>
}

Now I want to call the SaveToCacheAsync method dynamically like this:

private void SaveItems(IEnumerable<object> items, string typeName)
{
    object container = typeof(Manager)
        .GetRuntimeProperty(typeName).GetValue(null, null);
    var t = Type.GetType($"MyNameSpace.Models.{typeName}");

    // variant A - doesn't work, but makes clear what I want to do
    (container as IContainer<t>).SaveToCache(items);

    // variant B - doesn't work either
    var saveMethod = container.GetType()
        .GetRuntimeMethod("SaveToCache", new Type[] { Type.GetType($"System.Collections.Generic.List`1[{t.FullName}]") })
        .MakeGenericMethod(new Type[] { t });

    saveMethod.Invoke(container, new object[] { });
}

The project is a PCL, therefore I used GetRuntimeMethods.

6
  • Which class implements you IContainer<T> interface? Commented Feb 26, 2018 at 10:09
  • You can´t cast - which is a compile-time operation - with a type provided at runtime. In particular how should the compiler know anything about a type you only provide at runtime? It can´t, obiously. However you could create a non-generic base-interface that your generic one inherits from. Commented Feb 26, 2018 at 10:13
  • Container<T> implements IContainer<T>, I will edit the question. Commented Feb 26, 2018 at 10:13
  • 1
    What is your question? Commented Feb 26, 2018 at 10:15
  • Why even have the generic interface? Seems like you only need the method to be generic. Commented Feb 26, 2018 at 10:16

1 Answer 1

1

Your second version does not work because the method itself is not generic, the class is, and the Type instance you have is already an instantiated generic type since you get it form an object instance. While this version works it is not ideal as it involves using reflection to call the method which is slow and generally seems like a code smell

var saveMethod = container.GetType()
    .GetRuntimeMethod("SaveToCache", new Type[] { typeof(IEnumerable<>).MakeGenericType(t) })
    .Invoke (container, new object[] { items });

A better approach would be to have a non generic version of your interface (much like IEnumerable<T> and IEnumerable)

public interface IContainer
{
    IEnumerable SaveToCache(IEnumerable models);
}
public interface IContainer<T> : IContainer
{
    IEnumerable<T> SaveToCache(IEnumerable<T> models);
}

Your class can implement IContainer explicitly to avoid the non generic method being called and use it only in the context of your SaveItems method

public class Container<T> : IContainer<T>
{
    public IEnumerable<T> SaveToCache(IEnumerable<T> models)
    {
        return models;
    }

    IEnumerable IContainer.SaveToCache(IEnumerable models)
    {

    }
}

var container = new Container<string>();
container.SaveToCache(new string[] { "" }); // The generic method is avaiable if we have an referecne to the class
container.SaveToCache(new int[] { 0 });// And this will be a compile time error as expected

IContainer icontainer = container;
icontainer.SaveToCache(new string[] { "" }); // The non genric method will be called 
icontainer.SaveToCache(new int[] { 0 });// And this will be a runtime time error 
Sign up to request clarification or add additional context in comments.

7 Comments

Your syntax typeof(IEnumerable<>).MakeGenericType(t) isn't working for me, I will try the non generic interface...
@DanielR. any specific error you are getting ? I changed it after posting as in missed passing the parameter, but it shoudl work
The usage of type "IEnumerable<T>" (generic) requires 1-typeargument.
@DanielR. That is strange, you can't declare variables of unintsnatiated generics, but you can use them in typeof I did not check on PCL, but this is a language feature and should not depend on this. I am not at PC right now but I will check as soon as I get to one
@DanielR. I have tried to compile the code in a PCL, a .NET Standard Library and a .NET Core Library, it compiles in all versions, I am not sure why this error occurs for you.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.