.net 泛型和松耦合:Can类<;T>;在没有类型假设的情况下是解耦的吗?

.net 泛型和松耦合:Can类<;T>;在没有类型假设的情况下是解耦的吗?,.net,generics,reflection,dependency-injection,loose-coupling,.net,Generics,Reflection,Dependency Injection,Loose Coupling,我一直在玩松散耦合的数据访问层。我发现依赖注入过程非常有用,但在考虑使用泛型时遇到了一些难题 有没有办法让一个支持泛型类型参数的类真正做到解耦和类型安全?我担心的是,即使您写入一个公共接口,如果派生类型与您最初编写的实体不同,那么您也可能会遇到一些编译器可能无法捕获的严重运行时错误 问题是,当我编写代码从数据库获取数据并为我的对象添加水合物时,在下一层实现它时,我面临一个难题。如果我传入一个类,比如下面的Foo2,我可以中断代码,因为没有“隐式”转换。我一直在使用reflection来尝试放松一

我一直在玩松散耦合的数据访问层。我发现依赖注入过程非常有用,但在考虑使用泛型时遇到了一些难题

有没有办法让一个支持泛型类型参数的类真正做到解耦和类型安全?我担心的是,即使您写入一个公共接口,如果派生类型与您最初编写的实体不同,那么您也可能会遇到一些编译器可能无法捕获的严重运行时错误

问题是,当我编写代码从数据库获取数据并为我的对象添加水合物时,在下一层实现它时,我面临一个难题。如果我传入一个类,比如下面的Foo2,我可以中断代码,因为没有“隐式”转换。我一直在使用reflection来尝试放松一些,但我不断地回到这个问题上,当从数据库中获取数据时,我需要一个具体的类型。然后,该类型会在类型转换和类型保证方面产生问题。此外,如果我想抽象实体库中所有类型的所有方法,我可以通过反射来实现,但我仍然遇到这样一个问题:泛型只能显式地对“where T:ISomeInterface”语句进行类型保证。最后,如果我们有更多的派生类型或者从接口分支形成新类型的类型,这个模型就会崩溃。如果认为我需要为每种类型实现新的数据访问对象,就会迫使数据访问层进行更改。这打破了我心目中松耦合的定义

所有这些似乎都迫使我回到问题上来——泛型能否以真正松耦合的方式使用?如果是的话,你能提供哪些参考资料

简化示例:

public interface IEntity
{
    // stuff for state and methods ...
}
public interface IRepository<T> where T : IEntity
{
    void Save(out int id, T obj);
    T Load(int id);
}
public interface IFoo : IEntity
{
    int Id { get; set; }
    //All other IEntities goodness
    //Some new goodness specific to Foo
}
//Concrete Entities:
public class Foo : IFoo
{
    // blah blah
}
public class Foo2 : IFoo
{
    // new blah blah
}

public class FooRepository : IRepository<Foo> //OOPS, Looks like we have settled in on a concrete type!
{

    public void Save(out int id, Foo obj)
    {
        // ADO.NET code to access Sql ...
        id = 1;// this would actually be the result of the Sql insert output parameter
        return;
    }

    public Foo Load(int id)
    {
        Foo foo = new Foo();
        // ADO.Net code to access Sql
        return foo;
    }
}
公共接口的可扩展性
{
//状态和方法的东西。。。
}
公共接口i假设,其中T:i
{
无效保存(out int id,T obj);
T载荷(int-id);
}
公共接口IFoo:IEntity
{
int Id{get;set;}
//所有其他的美德
//一些新的福特有的善
}
//具体实体:
公共类Foo:IFoo
{
//废话
}
公共类Foo2:IFoo
{
//新的废话
}
公共类FooRepository:IRepository//OOPS,看起来我们已经确定了一个具体的类型!
{
公共无效保存(out int id,Foo obj)
{
//访问Sql的ADO.NET代码。。。
id=1;//这实际上是Sql insert输出参数的结果
返回;
}
公共Foo加载(int-id)
{
Foo-Foo=新的Foo();
//访问Sql的ADO.Net代码
返回foo;
}
}

那么,您将如何处理能够处理任何IFoo派生对象的代码,并且仍然能够返回完全形成的具体类型,而不管程序员在这条路上做了什么?最好抛弃泛型部分,坚持依赖注入吗?任何参考、指导等都会很好

对于这里遇到的问题,您可以始终使用
typeof
(或者可能是另一种操作符/方法)来获取对象的动态类型。这样,您可以在遇到某些铸造错误之前始终执行检查

您可以将具体类型限制设置为顶级类型,但这实际上违背了泛型的目的

否则,我真的不知道如何克服你的问题。如果使用泛型,重点是添加松散耦合和对类型不可知的泛型操作。唯一可以检索它的方法是键入,然后重铸,捕捉边缘案例以防止铸造错误。关于你的问题:

泛型能以真正松耦合的方式使用吗

我不太明白你的意思?从语义上来说,你当然可以。这实际上是泛型的目的之一

那么,您将如何处理能够处理任何IFoo派生对象的代码,并且仍然能够返回完全形成的具体类型,而不管程序员在这条路上做了什么

这也相当模糊。我可以写:

public SomeType method(IFoo obj)
{
...
}
这仍然可以处理任何IFoo。这不需要泛型。如果要具体返回传入内容的类型,则:

public T method<T>(IFoo obj) where T:IFoo
{
    return (T)obj;
}
public T方法(IFoo obj),其中T:IFoo
{
返回(T)obj;
}

希望这有帮助。如果我做错了什么事,请滚开。

我不得不承认,我对你的难题感到有点困惑;我不确定会是什么

生成具体类型的存储库显然必须知道如何创建它们。为什么不为每种类型创建一个存储库,以便每种类型都实现
IRepository
?这样,您就可以将具体实现留给DI容器的配置

例如,在ninject中,我会写一些类似于

Bind<IRepository<IFoo>>.To<Foo2Repository>()
Bind.To()
来设置这个。如果您需要更细粒度的控制,我所知道的大多数容器都支持某种方式的作用域,这样绑定只在某些条件下有效


我是否误解了什么,或者这是否解决了您的问题?

您可以在

class BaseFooRepository<TFoo> : IRepository<TFoo> where TFoo : IFoo
class BaseFooRepository:IRepository其中TFoo:IFoo
然后将更具体的代码放入

class Foo2Repository : BaseFooRepository<Foo2>
class Foo2Repository:BaseFooRepository

我知道这个问题不是100%完全形成的。我不想在这个问题上深入讨论,因为你的总体评论确实与我正在玩的一些东西一致。你最后的结构很有趣。但是,如果我没记错的话,如果您在类上强制类型约束,则不允许您在方法上强制条件。问题的一部分是我一直在使用一个更复杂的反射类,它允许我传入任何泛型类型,然后返回“Save”和