Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#使用泛型方法为泛型类创建接口_C#_Generics - Fatal编程技术网

C#使用泛型方法为泛型类创建接口

C#使用泛型方法为泛型类创建接口,c#,generics,C#,Generics,假设我有这段代码 public interface IFoo { } public abstract class FooBase<TModel> : IFoo { public T Create<T>() where T : TModel; } public class Foo : FooBase<ModelBase> { public TModel Create<TModel>() { return A

假设我有这段代码

public interface IFoo
{
}

public abstract class FooBase<TModel> : IFoo
{
    public T Create<T>() where T : TModel;
}

public class Foo : FooBase<ModelBase>
{
    public TModel Create<TModel>()
    {
        return Activator.CreateInstance(typeof(TModel));
    }
}

public abstract class ModelBase
{
}

public class ModelFoo : ModelBase
{
}

public class ModelBar : ModelBase
{
}
可能吗?你是说

ModelBar bar = FooProvider.Get<ModelBar>().Create<ModelBar>();
ModelBar=FooProvider.Get().Create();
或者更确切地说

ModelBar bar = FooProvider.Get<ModelBar>().Create();
ModelBar=FooProvider.Get().Create();
?

我发现前者有点奇怪,除非您有一些情况,第一个ModelBar实际上是ModelBarBase或IModelBar,而后一个ModelBar实际上是最终的可构造类型

无论如何,我也发现您的类布局有点奇怪,因为在您的代码示例中,Get()和Create()来自同一个类(Foo/FooBase)。我想你把SRP搞砸了

我建议:

public class FooProvider
{
    public static Provider<T> Get<T> { return new Provider<T>(); };
}

public class Provider<T>
{
    public T CreateDirect()
    {
        return Activator.Create<T>();
    }

    public TDerived CreateDerived<TDerived>() where TDerived : T
    {
        return Activator.Create<TDerived>();
    }
}
公共类提供程序
{
公共静态提供程序获取{返回新提供程序();};
}
公共类提供者
{
公共T CreateDirect()
{
返回Activator.Create();
}
public TDerived CreateDerived(),其中TDerived:T
{
返回Activator.Create();
}
}
在此设置中,您可以:

class IMyInterf {}
class MyType : IMyInterf {}
class MyChildType : MyType {}

MyType tmp1 = FooProvider.Get<MyType>().CreateDirect();

MyChildType tmp1 = FooProvider.Get<MyType>().CreateDerived<MyChildType>();

MyChildType tmp1 = FooProvider.Get<IMyInterf>().CreateDerived<MyChildType>();
类IMyInterf{}
类MyType:IMyInterf{}
类MyChildType:MyType{}
MyType tmp1=FooProvider.Get().CreateDirect();
MyChildType tmp1=FooProvider.Get().CreateDerived();
MyChildType tmp1=FooProvider.Get().CreateDerived();
这只是一个草图,没有经过编译,而是手写的,但它展示了总体思路

如果删除“CreateDirect”并将“CreateDerivated”重命名为仅创建,则会得到类似于代码的内容,但更简单。当然,如果您真的需要,您现在可以将这两个单独的类混合并压缩为一个类,但我看不出这有什么真正的意义:)

编辑:


当然,您可以引入一个
ProviderBase
和多个
OrangeProvider:ProviderBase
,而不是
ProviderBase
,这只是为了更容易地构建/找到合适的提供者,但是实际的
Get
必须返回实际的
ProviderBase
IProvider
随着问题的发展,我将发布第二个答案。下面是一个示例类层次结构:

  • 允许对许多模型类型使用相同的提供程序
  • 允许以一致的方式构造许多不同的提供程序和模型
  • 在编译时检查提供程序/模型兼容性
  • 使用过程中不需要浇铸
代码:

return (U)new Bar2();         // will not compile, U:Bar is not related to Bar2:Bar
return (U)(object)new Bar2(); // is ok: temporary cast to object 'erases' type information

返回
FooBase
而不是
IFoo
怎么样?因为调用
Get
时需要返回
FooBase
。正如您所看到的,
TModel
ModelBar
,而不是
ModelBase
,我无法将
Foo
转换为
FooBase
。我的设计思想是,我希望返回给定模型的提供程序,并且我希望在测试时能够替换此提供程序(使用模拟提供程序)。你的建议不允许这样。另外,一个供应商可以提供不同的(已知的)相关模型类型。我已经告诉过你这是一个草图/概述。最后两行显示,一个由“X”构成的提供者typef可以构造“Y”或“Z”,因此实现了多个类型的提供者typef。模拟/替换提供程序进行测试很简单:不再从
Get
-返回
IProvider
-现在您的静态FooProvider可以在测试环境中返回模拟。我的意思是,即使支持模拟,仍然没有必要混合使用工厂/提供者/模型类。我来自Java背景,我尝试做的事情相当简单,因为泛型的行为不同。所以,您的意思是,我需要为每种模型类型提供一个提供者?我刚刚发布了第二个示例。请看一看。您可以在代码中进行更强的编译时检查,以确定使用
new()
通用约束创建新实例是否会成功:
U Create(),其中U:T,new()
,这将使您能够简单地
返回新的U()而不是
返回Activator.CreateInstance()
。是的!我从问题中复制了对象创建代码,我认为它将被更复杂的东西所取代,因为Activator可以接受Construction参数,而
new()
约束不能(至少从.Net4/.5开始)。我不想让示例变得过于复杂。事实上,由于我已经编写了3个不同的示例提供程序,我已经将
WhateverProvider
升级为使用
new()
约束。谢谢你的建议!所以,这看起来很像我最初的实现。所有这些告诉我的是,我无法调用
ProviderFactory.Get()
,这正是我试图做的。谢谢你的时间!你可以做到。ProviderFactory.Get().Create()将编译-在上面的示例中,您必须纠正的唯一一件事是让Get实现识别Foo2并为其返回正确的提供程序(这里,一个
FooProvider
WhateverProvider
,因为它们都可以构造Foo2。首先代表Foo继承,其次代表IWhatever实现)
public class FooProvider
{
    public static Provider<T> Get<T> { return new Provider<T>(); };
}

public class Provider<T>
{
    public T CreateDirect()
    {
        return Activator.Create<T>();
    }

    public TDerived CreateDerived<TDerived>() where TDerived : T
    {
        return Activator.Create<TDerived>();
    }
}
class IMyInterf {}
class MyType : IMyInterf {}
class MyChildType : MyType {}

MyType tmp1 = FooProvider.Get<MyType>().CreateDirect();

MyChildType tmp1 = FooProvider.Get<MyType>().CreateDerived<MyChildType>();

MyChildType tmp1 = FooProvider.Get<IMyInterf>().CreateDerived<MyChildType>();
public interface IWhatever { }

public class Foo { }
public class Foo2 : Foo, IWhatever { }

public class Bar { }
public class Bar2 : Bar { }
public class Bar3 : Bar, IWhatever { }


public interface IModelProvider<T>
{
    U Create<U>() where U : T;
}

public class FooProvider : IModelProvider<Foo>
{
    public U Create<U>() where U : Foo
    {
        // create a proper "U" - for example Foo or Foo2
        return Activator.CreateInstance<U>(); // simpliest
    }
}

public class BarProvider : IModelProvider<Bar>
{
    public U Create<U>() where U : Bar
    {
        // create a proper "U" - for example Bar, Bar2 or Bar3
        // more verbose
        if (typeof(U) == typeof(Bar)) return (U)new Bar();
        if (typeof(U) == typeof(Bar2)) return (U)(object)new Bar2();
        if (typeof(U) == typeof(Bar3)) return (U)(object)new Bar3();

        throw new Exception();
    }
}

public class WhateverProvider : IModelProvider<IWhatever>
{
    public U Create<U>() where U : IWhatever, new()
    {
        // create a proper "U" - for example Foo2 or Bar3
        return new U(); // really the simpliest
    }
}
public class ProviderFactory
{
    public static IModelProvider<T> Get<T>() where T : new()
    {
        // somehow choose a provider for T, dumb implementation just for example purposes
        if (typeof(T) == typeof(Foo)) return (IModelProvider<T>)new FooProvider();
        if (typeof(T) == typeof(Bar)) return (IModelProvider<T>)new BarProvider();
        if (typeof(T) == typeof(IWhatever)) return (IModelProvider<T>)new WhateverProvider();

        return VeryGenericProvider<T>();
    }
}

public static class ProviderTest
{
    public static void test()
    {
        Foo foo = ProviderFactory.Get<Foo>().Create<Foo>();
        Foo2 foo2 = ProviderFactory.Get<Foo>().Create<Foo2>();

        // Bar2 bar2 = ProviderFactory.Get<Foo>().Create<Bar2>(); - compile error
        Bar2 bar2 = ProviderFactory.Get<Bar>().Create<Bar2>(); // - ok!

        Bar3 bar3 = ProviderFactory.Get<IWhatever>().Create<Bar3>();
    }
}
return (U)new Bar(); // is ok because U is constrained to 'Bar'
return (U)new Bar2();         // will not compile, U:Bar is not related to Bar2:Bar
return (U)(object)new Bar2(); // is ok: temporary cast to object 'erases' type information