C# 通用工厂法铸造问题

C# 通用工厂法铸造问题,c#,generics,factory,C#,Generics,Factory,尝试创建工厂以返回通用接口(如下所示),但出现错误: 无法将IFinancialsSyncService隐式转换为IFinancialsSyncService。存在明文转换,是否缺少强制转换 但是,如果我显式地强制转换它,我会得到一个强制转换是冗余的错误以及第一个错误 return (IFinancialsSyncService<Vendor, QuickBooksVendor>)new QuickbooksVendorService(); 并将其替换为以下内容: var qbEn

尝试创建工厂以返回通用接口(如下所示),但出现错误:

无法将
IFinancialsSyncService
隐式转换为
IFinancialsSyncService
。存在明文转换,是否缺少强制转换

但是,如果我显式地强制转换它,我会得到一个
强制转换是冗余的
错误以及第一个错误

return (IFinancialsSyncService<Vendor, QuickBooksVendor>)new QuickbooksVendorService();
并将其替换为以下内容:

var qbEntityService = EntityServiceFactory.Create(enumDataElement);

这个工厂会是什么样子?

这与利斯科夫的替代原理有关。假设您的泛型类型是接口的一个属性:

public class QuickbooksVendorService : IFinancialsSyncService<Vendor, QuickBooksVendor>
public interface IFinancials { }

public interface IFinancialsSyncService
{
  IFinancials Financials { get; set; }
}
现在我们实现以下接口:

public class Financials : IFinancials {}

public class FinancialsSyncService : IFinancialSyncService
{
  public Financials Financials { get; set; }
}
这将导致编译器错误:

编译错误:“Program.FinancialSyncService”未实现接口成员“Program.IFinancialsSyncService.Financials”Program.FinancialSyncService.Financials无法实现Program.IFinancialsSyncService.Financials,因为它没有匹配的返回类型“Program.IFinancials”

这两个问题都有相同的问题。在我的示例中,接口声明结果的类型为
IFinancials
,但它是更具体的派生类型
Financials
,即使放置在属性中的任何有效值满足接口,它不能替换为从
IFinancials
派生的任何值,只能替换为从
Financials
派生的类型

因此,如果您的代码看起来像:

public interface IFinancialsSyncService<TEntity>
   where TEntity : IEntity
{
  TEntity Financials { get; set; }
}
公共接口IFinancialsSyncService
其中tenty:tenty
{
TEntity Financials{get;set;}
}
然后创建一个类:

public class QuickbooksVendorService : IFinancialSyncService<Vendor>
{
  public Vendor Financials { get; set; }
}
公共类QuickbooksVendorService:IFinancialSyncService
{
公共供应商财务{get;set;}
}

但是,现在
QuickbooksVendorService
IFinancialSyncService
而不是
IFinancialSyncService
,因为该属性是派生类型。即使您没有此特定属性,它仍然会导致相同的问题,即泛型类型比接口更具体。

使用工厂方法和适配器模式

switch (enumDataElement)
{
    //Export jobs
    case DataElement.Item:
        var itemService = new QuickbooksItemService();
        exportResult = itemService.UpdateMozzoEntityWithFinancialsId(session, response, EntityId, intUserId);
        break;

    case DataElement.Vendor:
        var VendorService = new QuickbooksVendorService();
        exportResult = UpdateMozzoEntityWithFinancialsId(new QuickbooksVendorService(),session, response, EntityId, intUserId);
        break;

    case DataElement.Bill:
        var billService = new QuickbooksBillService();
        exportResult = billService.UpdateMozzoEntityWithFinancialsId(session, response, intUserId);
        break;

    case DataElement.PurchaseOrder:
        var qbPOService = new QuickbooksPurchaseOrderService();
        exportResult = qbPOService.UpdateMozzoEntityWithFinancialsId(session, response, intUserId);           
        break;

    case DataElement.SalesReceipt:
        var salesReceiptService = new QuickbooksSalesReceiptService();
        exportResult = salesReceiptService.UpdateStratusEntityWithFinancialsId(session, response, intUserId);
        break;
}
   [TestFixture]
    public class Class1
    {

        [Test]
        public void Go()
        {
            var qbItem = Export(1);
            var qbVendor= Export(2);
            var qbSales= Export(3);
        }

        public qbEntityService Export(int number)
        {
            var qb = Class1.Create(number);
            return qb.UpdateMozzoEntityWithFinancialsId();
        }

        public static IEntityService Create(int enumDataElement)
        {
            switch (enumDataElement)
            {
                case 1:
                    return new QuickbooksItemService();
                case 2:
                    return new QuickbooksVendorService();
                case 3:
                    return new QuickbooksSalesReceiptServiceAdapter(new QuickbooksSalesReceiptService());
                default:
                    throw new Exception();
            }
        }
    }

    public interface IEntityService
    {
        qbEntityService UpdateMozzoEntityWithFinancialsId();
    }

    public class qbEntityService
    {
    }

    public class QuickbooksItemService : IEntityService
    {
        public qbEntityService UpdateMozzoEntityWithFinancialsId()
        {
            Console.WriteLine("I am QuickbooksItemService, performing UpdateMozzoEntityWithFinancialsId");
            return new qbEntityService();
        }
    }

    public class QuickbooksVendorService : IEntityService
    {
        public qbEntityService UpdateMozzoEntityWithFinancialsId()
        {
            Console.WriteLine("I am QuickbooksVendorService, performing UpdateMozzoEntityWithFinancialsId");
            return new qbEntityService();
        }
    }

    public class QuickbooksSalesReceiptService
    {
        public qbEntityService UpdateStratusEntityWithFinancialsId()
        {
            Console.WriteLine("I am QuickbooksSalesReceiptService, performing UpdateStratusEntityWithFinancialsId");
            return new qbEntityService();
        }
    }


    public class QuickbooksSalesReceiptServiceAdapter : IEntityService
    {
        private QuickbooksSalesReceiptService adaptee;

        public QuickbooksSalesReceiptServiceAdapter(QuickbooksSalesReceiptService adaptee)
        {
            this.adaptee = adaptee;
        }

        public qbEntityService UpdateMozzoEntityWithFinancialsId()
        {
            return adaptee.UpdateStratusEntityWithFinancialsId();
        }
    }

什么是供应商类型?它是否实现了智能?请检查QuickBooksVendor服务是否正确实现了IFinancialsSyncService。同时签入您的泛型方法TEntity实现IEntity和IFinancials,TQuickBooksEntity实现IQuickBooksEntity。@maxspan是的,它们都实现了正确的接口。谢谢Erik,因此您无法返回更具体的类型。我还有一些其他与实体相关的服务,类似于
QuickBooksVendorService
,它们都符合相同的接口。我正在寻找一个工厂,根据输入类型返回正确的一个。我只需要使用两种方法,它们都是通用的,都是接口定义的一部分。那么,我如何创建一个工厂来返回这些服务中的一项……工厂的常见返回类型是什么?还是我走错了路?注意,已更新的问题显示了我试图消除的内容。我想问您为什么要返回通用接口
InterfaceOf
,而不仅仅是接口
Interface
。你没有说谁在使用结果,所以很难知道。是的,我能够从接口中删除返回
tenty
TQuickBooksEntity
的方法,并删除接口的那些限定符。工厂工作正常,然后只返回接口
IFinancialSyncService
。但是我想将这些方法恢复到接口。主要原因是,由于这是一个适配器类型的项目,它正在检索QuickBooks实体,如发票,然后将其转换为我们应用程序版本的发票,然后导入我们的应用程序数据库。@ChadRichardson您需要修复第59行和第62行。@ChadRichardson删除了更多未使用的泛型。
   [TestFixture]
    public class Class1
    {

        [Test]
        public void Go()
        {
            var qbItem = Export(1);
            var qbVendor= Export(2);
            var qbSales= Export(3);
        }

        public qbEntityService Export(int number)
        {
            var qb = Class1.Create(number);
            return qb.UpdateMozzoEntityWithFinancialsId();
        }

        public static IEntityService Create(int enumDataElement)
        {
            switch (enumDataElement)
            {
                case 1:
                    return new QuickbooksItemService();
                case 2:
                    return new QuickbooksVendorService();
                case 3:
                    return new QuickbooksSalesReceiptServiceAdapter(new QuickbooksSalesReceiptService());
                default:
                    throw new Exception();
            }
        }
    }

    public interface IEntityService
    {
        qbEntityService UpdateMozzoEntityWithFinancialsId();
    }

    public class qbEntityService
    {
    }

    public class QuickbooksItemService : IEntityService
    {
        public qbEntityService UpdateMozzoEntityWithFinancialsId()
        {
            Console.WriteLine("I am QuickbooksItemService, performing UpdateMozzoEntityWithFinancialsId");
            return new qbEntityService();
        }
    }

    public class QuickbooksVendorService : IEntityService
    {
        public qbEntityService UpdateMozzoEntityWithFinancialsId()
        {
            Console.WriteLine("I am QuickbooksVendorService, performing UpdateMozzoEntityWithFinancialsId");
            return new qbEntityService();
        }
    }

    public class QuickbooksSalesReceiptService
    {
        public qbEntityService UpdateStratusEntityWithFinancialsId()
        {
            Console.WriteLine("I am QuickbooksSalesReceiptService, performing UpdateStratusEntityWithFinancialsId");
            return new qbEntityService();
        }
    }


    public class QuickbooksSalesReceiptServiceAdapter : IEntityService
    {
        private QuickbooksSalesReceiptService adaptee;

        public QuickbooksSalesReceiptServiceAdapter(QuickbooksSalesReceiptService adaptee)
        {
            this.adaptee = adaptee;
        }

        public qbEntityService UpdateMozzoEntityWithFinancialsId()
        {
            return adaptee.UpdateStratusEntityWithFinancialsId();
        }
    }