繁体   English   中英

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 包含一个简单的类和一个方法,从 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# 那样支持协变/逆变。 有关于这一个开放的问题在这里

因此,对IAggregateEvent<IIdentity>显式(静态)转换在您的情况下不起作用。

然而,一切都没有丢失,因为您可以求助于动态向上转换:

let importEvent = new ImportEvent(unbox entityImported, null)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM