简体   繁体   English

C#使用Type参数将对象转换为通用接口

[英]C# Cast object to generic interface with Type parameter

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: 我在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: 现在我想动态调用SaveToCacheAsync方法,如下所示:

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 . 该项目是PCL,因此我使用了GetRuntimeMethods

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. 您的第二个版本不起作用,因为该方法本身不是通用的,类是,并且您拥有的Type实例已经是实例化的泛型类型,因为您从它获取它形成一个对象实例。 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 ) 更好的方法是拥有一个非通用版本的接口(很像IEnumerable<T>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 您的类可以显式实现IContainer以避免调用非泛型方法,并仅在SaveItems方法的上下文中使用它

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 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM