Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.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# 4.0 寻找一个合适的方法来实现我的通用工厂_C# 4.0_Factory Pattern - Fatal编程技术网

C# 4.0 寻找一个合适的方法来实现我的通用工厂

C# 4.0 寻找一个合适的方法来实现我的通用工厂,c#-4.0,factory-pattern,C# 4.0,Factory Pattern,我正在努力实现一个工厂对象。以下是上下文: 我在一个定制商店的项目中。为了读取/写入记录,我在POCO模型/分离存储库中编写了以下代码: public class Id { /* skip for clarity*/} // My custom ID representation public interface IId { Id Id { get; set; } } public interface IGenericRepository<T> where T : IId

我正在努力实现一个工厂对象。以下是上下文:

我在一个定制商店的项目中。为了读取/写入记录,我在POCO模型/分离存储库中编写了以下代码:

public class Id { /* skip for clarity*/} // My custom ID representation

public interface IId
{
    Id Id { get; set; }
}
public interface IGenericRepository<T> where T : IId
{
    T Get(Id objectID);
    void Save(T @object);
}
public interface IContext
{
    TRepository GetRepository<T, TRepository>() 
        where TRepository : IGenericRepository<T> 
        where T:IId;
    IGenericRepository<T> GetRepository<T>() 
        where T:IId;
}
public class Id{/*为清楚起见跳过*/}//我的自定义Id表示
公共接口IId
{
Id{get;set;}
}
公共接口IGenericRepository,其中T:IId
{
T Get(Id objectID);
无效保存(T@object);
}
公共接口IContext
{
TRepository GetRepository()
存储位置:IGenericRepository
式中T:IId;
IGenericRepository GetRepository()
式中T:IId;
}
我的IContext接口定义了两种存储库。 前者适用于只有get/save方法的标准对象,后者允许我为特定类型的对象定义特定的方法。例如:

public interface IWebServiceLogRepository : IGenericRepository<WebServiceLog>
{
    ICollection<WebServiceLog> GetOpenLogs(Id objectID);
}
公共接口IWebServiceLogRepository:IGenericRepository { ICollection GetOpenLogs(Id objectID); } 这是消费代码,我可以做其中一个:

  • MyContext.GetRepository().Get(myID)-->标准获取
  • MyContext.GetRepository().GetOpenLogs(myID)-->特定操作
由于大多数对象存储库仅限于获取和保存操作,因此我编写了一个通用存储库:

public class BaseRepository<T> : IGenericRepository<T>
    where T : IId, new()
{
    public virtual T Get(Id objectID){ /* provider specific */ }
    public void Save(T @object) { /* provider specific */ }
}
internal class WebServiceLogRepository: BaseRepository<WebServiceLog>, IWebServiceLogRepository
{
    public ICollection<WebServiceLog> GetByOpenLogsByRecordID(Id objectID)
    {
        /* provider specific */
    }
}
公共类基存储库:IGenericRepository
其中T:IId,new()
{
公共虚拟T Get(Id objectID){/*特定于提供程序的*/}
public void Save(T@object){/*特定于提供程序的*/}
}
对于自定义存储库,我只是继承了基本存储库:

public class BaseRepository<T> : IGenericRepository<T>
    where T : IId, new()
{
    public virtual T Get(Id objectID){ /* provider specific */ }
    public void Save(T @object) { /* provider specific */ }
}
internal class WebServiceLogRepository: BaseRepository<WebServiceLog>, IWebServiceLogRepository
{
    public ICollection<WebServiceLog> GetByOpenLogsByRecordID(Id objectID)
    {
        /* provider specific */
    }
}
内部类WebServiceLogRepository:BaseRepository、IWebServiceLogRepository
{
公共ICollection GetByOpenLogsByRecordID(Id objectID)
{
/*特定于提供商*/
}
}
上面的一切都还可以(至少我认为还可以)。我现在正在努力实现MyContext类。我在我的项目中使用MEF用于其他目的。但由于MEF还不支持通用的导出,我没有找到实现目标的方法

我的上下文类现在看起来像:

[Export(typeof(IContext))]
public class UpdateContext : IContext
{
    private System.Collections.Generic.Dictionary<Type, object> m_Implementations;

    public UpdateContext()
    {
        m_Implementations = new System.Collections.Generic.Dictionary<Type, object>();
    }
    public TRepository GetRepository<T, TRepository>()
        where T : IId
        where TRepository : IGenericRepository<T>
    {
        var tType = typeof(T);
        if (!m_Implementations.ContainsKey(tType))
        {
            /* this code is neither working nor elegant for me */
            var resultType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(
                (a) => a.GetTypes()
                ).Where((t)=>t.GetInterfaces().Contains(typeof(TRepository))).Single();

            var result = (TRepository)resultType.InvokeMember("new", System.Reflection.BindingFlags.CreateInstance, null, null, new object[] { this });

            m_Implementations.Add(tType, result);
        }
        return (TRepository)m_Implementations[tType];
    }

    public IGenericRepository<T> GetRepository<T>() where T : IId
    {
        return GetRepository<T, IGenericRepository<T>>();
    }
}
[导出(typeof(IContext))]
公共类UpdateContext:IContext
{
private System.Collections.Generic.Dictionary m_实现;
公共UpdateContext()
{
m_Implementations=new System.Collections.Generic.Dictionary();
}
公共存储库GetRepository()
T:IId在哪里
存储位置:IGenericRepository
{
var tType=类型(T);
if(!m_Implementations.ContainsKey(tType))
{
/*这个代码对我来说既不起作用也不优雅*/
var resultType=AppDomain.CurrentDomain.GetAssemblys()。SelectMany(
(a) =>a.GetTypes()
)其中((t)=>t.GetInterfaces()包含(typeof(TRepository))).Single();
var result=(TRepository)resultType.InvokeMember(“新建”,System.Reflection.BindingFlags.CreateInstance,null,null,新对象[]{this});
m_Implementations.Add(tType,result);
}
返回(TRepository)m_实现[tType];
}
公共IGenericRepository GetRepository(),其中T:IId
{
返回GetRepository();
}
}

我希望能得到一些帮助,用这个非常常见的场景来解惑我的头脑

我不确定我是否正确地理解了你,但我认为你可能把事情复杂化了。首先,确保您设计的代码独立于任何工厂、依赖项注入框架或组合框架

首先,让我们看看您希望您的调用代码是什么样子的,这就是您所说的:

MyContext.GetRepository<Customer>().Get(myID); --> standard get
MyContext.GetRepository<WebServiceLog, IWebServiceLogRepository>().GetOpenLogs(myID);
MyContext.GetRepository().Get(myID);-->标准件
MyContext.GetRepository().GetOpenLogs(myID);
你不必同意我下面的命名选择,但它表明了我对你的代码的理解,如果我错了,你可以告诉我。现在,我觉得打电话会更简单,就像这样:

RepositoryFactory.New<IRepository<Customer>>().Get(myId);
RepositoryFactory.New<IWebServiceLogRepository>().GetOpenLogs(myId);
public interface IRepository<T>
{
T Get(object Id);
T Save(T object);
}

public interface IWebServiceLogRepository: IRepository<WebServiceLog>
{
List<WebServiceLog> GetOpenLogs(object Id);
}
RepositoryFactory.New().Get(myId);
RepositoryFactory.New().GetOpenLogs(myId);
第1行: 因为这里的类型是IRepository,所以很清楚返回类型是什么,对于基础IRepository,T类型是什么

第2行: 工厂返回的类型是IWebServiceLogRepository。在这里,您不需要指定实体类型,您的接口在逻辑上已经实现了IRepository。无需再次指定此项

因此,这些的界面如下所示:

RepositoryFactory.New<IRepository<Customer>>().Get(myId);
RepositoryFactory.New<IWebServiceLogRepository>().GetOpenLogs(myId);
public interface IRepository<T>
{
T Get(object Id);
T Save(T object);
}

public interface IWebServiceLogRepository: IRepository<WebServiceLog>
{
List<WebServiceLog> GetOpenLogs(object Id);
}
公共接口IRepository
{
T Get(对象Id);
T保存(T对象);
}
公共接口IWebServiceLogRepository:IRepository
{
列出GetOpenLogs(对象Id);
}
现在我认为实现和工厂代码会更简单,因为工厂只需要知道一种类型。第1行的类型是IRepository,第2行的类型是IWebServiceLogRepository

试着这样做,然后试着重写代码,简单地找到实现这些类型的类并实例化它们

最后,就MEF而言,您可以继续使用它,但Castle Windsor确实会让您的工作更简单,因为它让您可以专注于您的体系结构和代码设计,而且使用起来非常简单。您只在应用程序启动代码中引用Castle。剩下的代码只是使用依赖注入模式设计的,该模式与框架无关

如果其中一些不清楚,请告诉我您是否希望我也用您的存储库的实现代码更新此答案

更新 下面是解析实现的代码。您没有使用Activator类,这让您自己变得更难了

如果您使用Activator,并且像我在下面的方法中所做的那样只使用一个泛型参数,那么应该可以。请注意,代码有点粗糙,但您可以理解:

public static T GetThing<T>()
        {
            List<Type> assemblyTypes = AppDomain.CurrentDomain.GetAssemblies()
                                        .SelectMany(s => s.GetTypes()).ToList();

            Type interfaceType = typeof(T);

            if(interfaceType.IsGenericType)
            {
                var gens = interfaceType.GetGenericArguments();
                List<Type> narrowed = assemblyTypes.Where(p => p.IsGenericType && !p.IsInterface).ToList();
                var implementations = new List<Type>();
                narrowed.ForEach(t=>
                {
                    try
                    {
                        var imp = t.MakeGenericType(gens);
                        if(interfaceType.IsAssignableFrom(imp))
                        {
                            implementations.Add(imp);     
                        }  
                    }catch
                    {
                    }
                });

                return (T)Activator.CreateInstance(implementations.First());
            }
            else
            {
                List<Type> implementations = assemblyTypes.Where(p => interfaceType.IsAssignableFrom(p) && !p.IsInterface).ToList();

                return (T)Activator.CreateInstance(implementations.First());
            }

        }
publicstatict GetThing()
{
列表