【问题标题】:C# Can I create a generic method or property inside a non-generic class that returns a different generic class?C# 我可以在返回不同泛型类的非泛型类中创建泛型方法或属性吗?
【发布时间】:2011-07-01 07:47:09
【问题描述】:

我有一个抽象的泛型类。我想在里面定义一个方法,这样我就不必在所有派生类中都这样做了。

基本上我需要根据泛型类的类型来获取存储库类。

我通过另一个非通用类获取存储库。

如何让该类根据通用调用者的类型返回通用存储库?

我希望有这样的东西。

public IRepository<T> Table<T>()
{
    return _container.Resolve<IRepository<T>>();
}

如果它是一个属性会更好。

【问题讨论】:

  • 该代码可以工作,那么问题是什么?
  • @Aliostad 编译器不同意类型“T”不能用作泛型类型或方法“Data.IRepository”中的类型参数“T”。没有从“T”到“IdentifiableModel”的装箱转换或类型参数转换
  • 好吧,如果我最后说 Where T : IdentifiableModel 就可以了。
  • 防止容器本身在该基类中。这是服务定位器模式的一种形式。尝试注入一个IRepositoryFactory,让您可以解析您的存储库。
  • @Steven 我对 DI 和 IOC 容器真的很陌生,感觉有点不知所措。我不确定我现在是否敢尝试添加工厂。

标签: c# generics methods properties


【解决方案1】:

C# 无法表达“self”类型,但您可以模拟它使用奇怪的循环模板模式 (CRTP)。

public class Base<TSelf> where TSelf : Base<TSelf> 
{
    // Make this a property if you want.
    public IRepository<TSelf> GetTable()
    {                   
        return _container.Resolve<IRepository<TSelf>>();          
    }
}

public class Derived : Base<Derived> {  }

用法:

IRepository<Derived> table = new Derived().GetTable();  

但这并不是万无一失的。有关详细信息,请阅读 Eric Lippert 的这篇博文:Curiouser and curiouser


另一方面,如果您只需要 _container.Resolve 调用的类型参数基于当前类型,但可以从该方法返回更通用的类型,则不必诉诸于此图案。您可以改用反射:

// If the container's Resolve method had an overload that 
// accepted a System.Type, it would be even easier.
public SomeBaseType GetTable()
{
   var repositoryType = typeof(IRepository<>).MakeGenericType(GetType());

   var result = _container.GetType()
                          .GetMethod("Resolve")
                          .MakeGenericMethod(repositoryType)
                          .Invoke(_container, null);

   return (SomeBaseType) result;     
}

【讨论】:

    【解决方案2】:

    我没有看到问题。您可以编写像这样编译的代码。这不能实现你想要的吗?

    interface IRepository<T>
    {
        T GetData();
    }
    
    class Container
    {
        private object[] data = null;
    
        public T Resolve<T>()
        {
            return(T)data.First(t => t.GetType() is T);
        }
    }
    
    abstract class Handler<T>
    {
        private Container _container;
    
        public IRepository<T> Table
        {
            get
            {
                return _container.Resolve<IRepository<T>>();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-24
      • 2011-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-16
      相关资源
      最近更新 更多