通用工厂方法铸造问题
Generic Factory Method Casting Issue
正在尝试为 return 通用接口(遵循 )创建工厂,但出现错误:
Can't implicitly convert IFinancialsSyncService<Vendor, QuickBooksVendor>
to IFinancialsSyncService<TEntity, TQuickBooksEntity>
. Anexplicit conversion exists, are you missing a cast?
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);
这个工厂会是什么样子?
这与里氏代换原则有关。想象一下,您的通用类型是接口的 属性:
public interface IFinancials { }
public interface IFinancialsSyncService
{
IFinancials Financials { get; set; }
}
现在我们实现这个接口:
public class Financials : IFinancials {}
public class FinancialsSyncService : IFinancialSyncService
{
public Financials Financials { get; set; }
}
这会导致编译器错误:
Compilation error: 'Program.FinancialsSyncService' does not implement interface member 'Program.IFinancialsSyncService.Financials'. 'Program.FinancialsSyncService.Financials' cannot implement 'Program.IFinancialsSyncService.Financials' because it does not have the matching return type of 'Program.IFinancials'.
两个问题都是同一个问题。在我的示例中,接口声明结果是 IFinancials
类型,但它是更具体的派生类型 Financials
并且即使放置在 属性 中的任何有效值都满足接口,它不能替换为派生自 IFinancials
的任何值,仅派生自 Financials
.
的类型
因此,如果您的代码如下所示:
public interface IFinancialsSyncService<TEntity>
where TEntity : IEntity
{
TEntity Financials { get; set; }
}
然后你创建一个 class:
public class QuickbooksVendorService : IFinancialSyncService<Vendor>
{
public Vendor Financials { get; set; }
}
但是,现在 QuickbooksVendorService
是 IFinancialSyncService<Vendor>
而不是 IFinancialSyncService<TEntity>
,因为 属性 是派生类型。即使你没有这个特定的 属性 它仍然会导致同样的问题,即泛型类型比接口更具体。
使用工厂方法和适配器模式
[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();
}
}
正在尝试为 return 通用接口(遵循
Can't implicitly convert
IFinancialsSyncService<Vendor, QuickBooksVendor>
toIFinancialsSyncService<TEntity, TQuickBooksEntity>
. Anexplicit conversion exists, are you missing a cast?
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);
这个工厂会是什么样子?
这与里氏代换原则有关。想象一下,您的通用类型是接口的 属性:
public interface IFinancials { }
public interface IFinancialsSyncService
{
IFinancials Financials { get; set; }
}
现在我们实现这个接口:
public class Financials : IFinancials {}
public class FinancialsSyncService : IFinancialSyncService
{
public Financials Financials { get; set; }
}
这会导致编译器错误:
Compilation error: 'Program.FinancialsSyncService' does not implement interface member 'Program.IFinancialsSyncService.Financials'. 'Program.FinancialsSyncService.Financials' cannot implement 'Program.IFinancialsSyncService.Financials' because it does not have the matching return type of 'Program.IFinancials'.
两个问题都是同一个问题。在我的示例中,接口声明结果是 IFinancials
类型,但它是更具体的派生类型 Financials
并且即使放置在 属性 中的任何有效值都满足接口,它不能替换为派生自 IFinancials
的任何值,仅派生自 Financials
.
因此,如果您的代码如下所示:
public interface IFinancialsSyncService<TEntity>
where TEntity : IEntity
{
TEntity Financials { get; set; }
}
然后你创建一个 class:
public class QuickbooksVendorService : IFinancialSyncService<Vendor>
{
public Vendor Financials { get; set; }
}
但是,现在 QuickbooksVendorService
是 IFinancialSyncService<Vendor>
而不是 IFinancialSyncService<TEntity>
,因为 属性 是派生类型。即使你没有这个特定的 属性 它仍然会导致同样的问题,即泛型类型比接口更具体。
使用工厂方法和适配器模式
[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();
}
}