2014-11-05 146 views
0

我都此类工作作为我的仓库:具有非泛型方法约束的泛型类?

public class Repository<T> where T : class, new() 
{ 
    public T GetByID(int id) 
    { 
     //Code... 
    }   
} 

但是也有少数情况下,我不想离开班级的默认公共构造(如需要一些逻辑某些特定型号的属性),像这样:

public class Person 
{ 
    public CPersonID PersonID { get; private set; } 

    //This shouldn't exist outside Person, and only Person knows the rules how to handle this 
    public class CPersonID 
    { 
     internal CPersonID() { } 
    } 
} 

这使得Repository模板类无效,因为new()约束。 我想做出这样的事情:

public class Repository<T> where T : class 
{ 
    //This function should be created only when the T has new() 
    public GetByID(int id) where T : new() 
    {    
    } 

    //And this could be the alternative if it doesn't have new() 
    public GetByID(T element, int id) 
    { 
    } 
} 

有什么办法,我可以做到这一点?

编辑:一Get方法例子:

public IList<T> GetAll() 
{ 
    IList<T> list = new List<T>(); 

    using(IConnection cn = ConnectionFactory.GetConnection()) 
    { 
     ICommand cm = cn.GetCommand(); 
     cm.CommandText = "Query"; 

     using (IDataReader dr = cm.ExecuteReader()) 
     { 
      while(dr.Read()) 
      { 
       T obj = new T(); //because of this line the class won't compile if I don't have the new() constraint 
       //a mapping function I made to fill it's properties 
       LoadObj(obj, dr); 
       list.Add(obj); 
      } 
     } 
    } 

    return list; 
} 
+1

为什么'Repository'需要'new()'约束呢? – 2014-11-05 12:44:51

+0

@dav_i由于'GetByID'和其他类似的'Get'方法,我创建了一个T的新实例,填充它的数据并返回它。 – Danicco 2014-11-05 12:46:15

+0

无法达到此目的,但也可以使用类似AutoMapper的库,并允许实施存储库,以确定如何将原始数据从存储库转换为要传递给自动映射器的数据传输对象。 – 2014-11-05 12:56:55

回答

2

随着Lasse V. Karlsen已经回答,这不是直接可能的。然而,你可以非常接近,足够接近实际的目的。

鉴于public class Repository<T> where T : class,您无法定义只有当T具有无参数构造函数时才存在的实例方法。你不需要那个。你只需要repository.GetByID(3)工作。如果GetByID是一个实例方法,但是如果它是扩展方法,并且扩展方法可以将要求添加到T,则这可以工作。

public static class RepositoryExtensions 
{ 
    public T GetByID(this Repository<T> repo, int id) where T : class, new() 
    { 
    ... 
    } 
} 

注意如果同名的实例方法已经存在的扩展方法不起作用,所以如果你有这个去了,你需要的GetByID既重载是扩展方法,不只是这一个。

实际的逻辑属于Repository类,但你可以转发到:

public class Repository<T> where T : class 
{ 
    internal T GetByIDImpl(int id, Func<T> factory) 
    { 
    ... 
    } 
} 

public static class RepositoryExtensions 
{ 
    public T GetByID(this Repository<T> repo, int id) where T : class, new() 
    { 
    return repo.GetByIDImpl(id,() => new T()); 
    } 
    public T GetByID(this Repository<T> repo, T element, int id) where T : class 
    { 
    return repo.GetByIDImpl(id,() => element); 
    } 
} 
2

不,你不能这样来做。

所有的约束都必须指定引入泛型参数的地方,在这种情况下是在类级别。

因此,你有两个选择:

  1. 添加, new()作为约束,限制使用存储库类的使用有一个公共的无参数的构造函数类型
  2. 没有将其添加为一个约束,而使用反射尝试在运行时构造对象

请注意,如果类型没有有效的构造函数,那么点2可能会失败(在运行时)。

你无法要求编译器创建一个能够调用特定方法的类,即有条件的,即。 “如果类型有构造函数,只让我调用GetByID”。

0

如果你想把它当作一个编译时间限制,你可以做

public class Class<T> where T : class 
{ 
    public void Method<U> where U : T, new() 
    { 
     // ... 
    } 
} 

但这有缺点,你必须做

new Class<HasConstructor>().Method<HasConstructor>(); 

作为类型不会隐式已接。好处是,下面不会编译:

new Class<NoConstructor>().Method<NoConstructor>();