通用工厂方法转换问题

时间:2019-06-20 21:08:47

标签: c# generics factory

尝试创建工厂以返回通用接口(在this answer之后),但出现错误:

  

无法将IFinancialsSyncService<Vendor, QuickBooksVendor>隐式转换为IFinancialsSyncService<TEntity, TQuickBooksEntity>。存在明显转换,您是否缺少演员表?

public class QuickBooksEntityServiceFactory
{
    public IFinancialsSyncService<TEntity, TQuickBooksEntity> Create<TEntity, TQuickBooksEntity>()
        where TEntity : class, IEntity, IFinancials, new()
        where TQuickBooksEntity : class, IQuickBooksEntity
    {

        if (typeof(TEntity) == typeof(QuickBooksVendor))
        {
            return new QuickbooksVendorService();
        }


        throw new InvalidOperationException();
    }
}

服务确认到IFinancialsSyncService界面:

public class QuickbooksVendorService : IFinancialsSyncService<Vendor, QuickBooksVendor>

但是,如果我将其显式转换,则仍然会遇到Cast is redundant错误和第一个错误。

return (IFinancialsSyncService<Vendor, QuickBooksVendor>)new QuickbooksVendorService();

因此错误使我感到困惑。我在做什么错了?

更新

这就是我要简化的内容。有许多与此类似的实例也调用了接口的其他常用方法。

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;
}

并替换为:

var qbEntityService = EntityServiceFactory.Create(enumDataElement);

这家工厂长什么样?

2 个答案:

答案 0 :(得分:1)

这与Liskov的替代原则有关。想象一下,您的通用类型是接口的属性:

public interface IFinancials { }

public interface IFinancialsSyncService
{
  IFinancials Financials { get; set; }
}

现在我们实现以下接口:

public class Financials : IFinancials {}

public class FinancialsSyncService : IFinancialSyncService
{
  public Financials Financials { get; set; }
}

这会导致编译器错误:

  

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

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

因此,如果您的代码如下所示:

public interface IFinancialsSyncService<TEntity>
   where TEntity : IEntity
{
  TEntity Financials { get; set; }
}

然后您创建一个类:

public class QuickbooksVendorService : IFinancialSyncService<Vendor>
{
  public Vendor Financials { get; set; }
}

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

答案 1 :(得分:-1)

使用Factory方法和适配器模式

   [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();
        }
    }
相关问题