Общий метод литья по методу фабрики - PullRequest
1 голос
/ 21 июня 2019

Попытка создать фабрику для возврата универсального интерфейса (после этого ответа ), но с ошибкой:

Невозможно неявно преобразовать 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 ]

1 голос
/ 21 июня 2019

Это связано с принципом замещения Лискова.Представьте, что ваш универсальный тип вместо этого является свойством интерфейса:

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

Однако теперь QuickbooksVendorService является IFinancialSyncService<Vendor>, а не IFinancialSyncService<TEntity>, поскольку свойство является производным типом.Даже если у вас не было этого конкретного свойства, оно все равно приводит к той же проблеме, что универсальный тип более специфичен, чем интерфейс.

0 голосов
/ 21 июня 2019

используйте заводской метод и шаблон адаптера

   [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();
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...