I have a Visual Studio solution with 3 projects named BaseCs, UseCs and UseFs (all .net core 3.1 libraries).
//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>'
()
No problem with Use.cs. However, the F# compiler refuses to accept the code, complaining that The type 'EntityImported' is not compatible with the type 'IAggregateEvent'
How do I get if F# UseFs.fs the same result as in C# UseCs.cs?
F# does not support covariance/contravariance like C# does. There is an open issue about this here.
Explicit (static) casting to IAggregateEvent<IIdentity>
does not work in your case because of this.
All is not lost, however, since you can resort to dynamic upcast:
let importEvent = new ImportEvent(unbox entityImported, null)