C#/F# 互操作性:不能在 F# 代码中使用 C# 类型
C#/F# interoperability: cannot use C# types in F# code
我有一个 Visual Studio 解决方案,其中包含 3 个名为 BaseCs、UseCs 和 UseFs 的项目(所有 .net 核心 3.1 库)。
- BaseCs 在 C# 中并且只有一个源文件Definitions.cs包含一系列类型定义
- UseCs 在 C# 中只有一个源文件 Use.cs 包含一个简单的 class 和一种方法,从 BaseCs
创建类型的实例
- UseFs 是 UseCs 的 F# 版本
//Definitions.cs
using System;
namespace BaseCs
{
public interface IIdentity
{
string Value { get; }
Guid GetGuid();
}
public abstract class Identity<T> : IIdentity where T : Identity<T>
{
public string Value { get; }
public Guid GetGuid()
{
throw new NotImplementedException();
}
}
public class EntityId : Identity<EntityId> { }
public interface IMessage
{
string SourceId { get; }
}
public interface IAggregateEvent : IMessage { }
public interface IAggregateEvent<out TIdentity> : IAggregateEvent
where TIdentity : IIdentity
{
TIdentity Id { get; }
}
public interface IAggregateEvent<out TIdentity, out TData> : IAggregateEvent<TIdentity>
where TIdentity : IIdentity
{
TData Data { get; }
}
public abstract class AggregateEvent<TIdentity, TData> : IAggregateEvent<TIdentity, TData> where TIdentity : IIdentity
{
protected AggregateEvent(TIdentity id, TData data, string sourceId)
{
this.Id = id;
this.Data = data;
this.SourceId = sourceId;
}
public TData Data { get; }
public TIdentity Id { get; }
public string SourceId { get; }
}
public interface IAuditedAggregateEvent : IAggregateEvent
{
EntityId EntityId { get; set; }
string EntitySortName { get; set; }
}
public interface IAuditedAggregateEvent<out TIdentity, out TData> : IAuditedAggregateEvent, IAggregateEvent<TIdentity, TData>
where TIdentity : IIdentity
{
}
public abstract class AuditedAggregateEvent<TIdentity, TData> : AggregateEvent<TIdentity, TData>, IAuditedAggregateEvent<TIdentity, TData> where TIdentity : IIdentity
{
public AuditedAggregateEvent(TIdentity id, TData data, string sourceId) : base(id, data, sourceId)
{ }
public EntityId EntityId { get; set; }
public string EntitySortName { get; set; }
}
public interface ISimpleAudit
{
EntityId CreatedBy { get; set; }
string CreatedBySortName { get; set; }
DateTimeOffset CreatedOn { get; set; }
EntityId UpdatedBy { get; set; }
string UpdatedBySortName { get; set; }
DateTimeOffset UpdatedOn { get; set; }
}
public partial class EntityData : ICloneable, ISimpleAudit
{
public object Clone()
{
throw new NotImplementedException();
}
public EntityId CreatedBy { get; set; }
public string CreatedBySortName { get; set; }
public DateTimeOffset CreatedOn { get; set; }
public EntityId UpdatedBy { get; set; }
public string UpdatedBySortName { get; set; }
public DateTimeOffset UpdatedOn { get; set; }
}
public interface IProtocol { }
public interface IAccountingServiceProtocol : IProtocol { }
public interface IEntityProtocol : IProtocol, IAccountingServiceProtocol { }
public interface IDataImportEvent
{
}
public interface IUnorderedEvent { }
public class EntityImported : AuditedAggregateEvent<EntityId, EntityData>, IEntityProtocol, IDataImportEvent, IUnorderedEvent
{
public EntityImported(EntityId id, EntityData data, string sourceId) : base(id, data, sourceId) { }
}
public interface ICommandId
{
Guid CommandId { get; }
}
public interface ICommand : IMessage, ICommandId
{ }
public interface IImportProtocol { }
public class ImportEvent : ICommand, IImportProtocol
{
public ImportEvent(IAggregateEvent<IIdentity> @event, string sourceId)
{
Event = @event;
SourceId = sourceId;
}
public static ImportEvent Of(IAggregateEvent<IIdentity> evt, string sourceId = null) => new ImportEvent(evt, sourceId);
public string SourceId { get; }
public Guid CommandId { get; }
public IAggregateEvent<IIdentity> Event { get; private set; }
}
}
//UseCs.cs
using BaseCs;
using System;
namespace UseCs
{
public class UseCs
{
void method()
{
var entityImported = new EntityImported(null, null, Guid.NewGuid().ToString());
var importEvent = new ImportEvent(entityImported, null);
}
}
}
//UseFs.fs
namespace UseFs
open BaseCs
open System
module UseFs =
let method() =
let entityImported = new EntityImported(null, null, Guid.NewGuid().ToString());
let importEvent = new ImportEvent(entityImported, null); //compiler error: The type 'EntityImported' is not compatible with the type 'IAggregateEvent<IIdentity>'
()
Use.cs 没问题。
但是,F#编译器拒绝接受代码,抱怨类型'EntityImported'与类型'IAggregateEvent'
不兼容
如果 F# UseFs.fs 与 C# UseCs.cs 中的结果相同,我如何获得?
F# 不像 C# 那样支持 covariance/contravariance。 here.
有一个未解决的问题
因此,显式(静态)转换为 IAggregateEvent<IIdentity>
在您的情况下不起作用。
然而,一切并没有丢失,因为您可以求助于动态向上转换:
let importEvent = new ImportEvent(unbox entityImported, null)
我有一个 Visual Studio 解决方案,其中包含 3 个名为 BaseCs、UseCs 和 UseFs 的项目(所有 .net 核心 3.1 库)。
- BaseCs 在 C# 中并且只有一个源文件Definitions.cs包含一系列类型定义
- UseCs 在 C# 中只有一个源文件 Use.cs 包含一个简单的 class 和一种方法,从 BaseCs 创建类型的实例
- UseFs 是 UseCs 的 F# 版本
//Definitions.cs
using System;
namespace BaseCs
{
public interface IIdentity
{
string Value { get; }
Guid GetGuid();
}
public abstract class Identity<T> : IIdentity where T : Identity<T>
{
public string Value { get; }
public Guid GetGuid()
{
throw new NotImplementedException();
}
}
public class EntityId : Identity<EntityId> { }
public interface IMessage
{
string SourceId { get; }
}
public interface IAggregateEvent : IMessage { }
public interface IAggregateEvent<out TIdentity> : IAggregateEvent
where TIdentity : IIdentity
{
TIdentity Id { get; }
}
public interface IAggregateEvent<out TIdentity, out TData> : IAggregateEvent<TIdentity>
where TIdentity : IIdentity
{
TData Data { get; }
}
public abstract class AggregateEvent<TIdentity, TData> : IAggregateEvent<TIdentity, TData> where TIdentity : IIdentity
{
protected AggregateEvent(TIdentity id, TData data, string sourceId)
{
this.Id = id;
this.Data = data;
this.SourceId = sourceId;
}
public TData Data { get; }
public TIdentity Id { get; }
public string SourceId { get; }
}
public interface IAuditedAggregateEvent : IAggregateEvent
{
EntityId EntityId { get; set; }
string EntitySortName { get; set; }
}
public interface IAuditedAggregateEvent<out TIdentity, out TData> : IAuditedAggregateEvent, IAggregateEvent<TIdentity, TData>
where TIdentity : IIdentity
{
}
public abstract class AuditedAggregateEvent<TIdentity, TData> : AggregateEvent<TIdentity, TData>, IAuditedAggregateEvent<TIdentity, TData> where TIdentity : IIdentity
{
public AuditedAggregateEvent(TIdentity id, TData data, string sourceId) : base(id, data, sourceId)
{ }
public EntityId EntityId { get; set; }
public string EntitySortName { get; set; }
}
public interface ISimpleAudit
{
EntityId CreatedBy { get; set; }
string CreatedBySortName { get; set; }
DateTimeOffset CreatedOn { get; set; }
EntityId UpdatedBy { get; set; }
string UpdatedBySortName { get; set; }
DateTimeOffset UpdatedOn { get; set; }
}
public partial class EntityData : ICloneable, ISimpleAudit
{
public object Clone()
{
throw new NotImplementedException();
}
public EntityId CreatedBy { get; set; }
public string CreatedBySortName { get; set; }
public DateTimeOffset CreatedOn { get; set; }
public EntityId UpdatedBy { get; set; }
public string UpdatedBySortName { get; set; }
public DateTimeOffset UpdatedOn { get; set; }
}
public interface IProtocol { }
public interface IAccountingServiceProtocol : IProtocol { }
public interface IEntityProtocol : IProtocol, IAccountingServiceProtocol { }
public interface IDataImportEvent
{
}
public interface IUnorderedEvent { }
public class EntityImported : AuditedAggregateEvent<EntityId, EntityData>, IEntityProtocol, IDataImportEvent, IUnorderedEvent
{
public EntityImported(EntityId id, EntityData data, string sourceId) : base(id, data, sourceId) { }
}
public interface ICommandId
{
Guid CommandId { get; }
}
public interface ICommand : IMessage, ICommandId
{ }
public interface IImportProtocol { }
public class ImportEvent : ICommand, IImportProtocol
{
public ImportEvent(IAggregateEvent<IIdentity> @event, string sourceId)
{
Event = @event;
SourceId = sourceId;
}
public static ImportEvent Of(IAggregateEvent<IIdentity> evt, string sourceId = null) => new ImportEvent(evt, sourceId);
public string SourceId { get; }
public Guid CommandId { get; }
public IAggregateEvent<IIdentity> Event { get; private set; }
}
}
//UseCs.cs
using BaseCs;
using System;
namespace UseCs
{
public class UseCs
{
void method()
{
var entityImported = new EntityImported(null, null, Guid.NewGuid().ToString());
var importEvent = new ImportEvent(entityImported, null);
}
}
}
//UseFs.fs
namespace UseFs
open BaseCs
open System
module UseFs =
let method() =
let entityImported = new EntityImported(null, null, Guid.NewGuid().ToString());
let importEvent = new ImportEvent(entityImported, null); //compiler error: The type 'EntityImported' is not compatible with the type 'IAggregateEvent<IIdentity>'
()
Use.cs 没问题。 但是,F#编译器拒绝接受代码,抱怨类型'EntityImported'与类型'IAggregateEvent'
不兼容如果 F# UseFs.fs 与 C# UseCs.cs 中的结果相同,我如何获得?
F# 不像 C# 那样支持 covariance/contravariance。 here.
有一个未解决的问题因此,显式(静态)转换为 IAggregateEvent<IIdentity>
在您的情况下不起作用。
然而,一切并没有丢失,因为您可以求助于动态向上转换:
let importEvent = new ImportEvent(unbox entityImported, null)