0

I need to implement an interface like this:

interface IEvent<T> : IEvent { T Data { get; } } 
public interface IEvent { Guid Id { get; set; } long Version { get; set; } long Sequence { get; set; } object Data { get; } Guid StreamId { get; set; } string StreamKey { get; set; } DateTimeOffset Timestamp { get; set; } string TenantId { get; set; } Type EventType { get; } string EventTypeName { get; set; } string DotNetTypeName { get; set; } } 

That's what I came up with:

type WrappedEvent<'T>(x: 'T) = interface Events.IEvent with member val Data = x with get member val DotNetTypeName = null with get, set member val EventType = null member val EventTypeName = null with get, set member val Id = Guid.Empty with get, set member val Sequence = int64 (0) with get, set member val StreamId = Guid.Empty with get, set member val StreamKey = null with get, set member val TenantId = null with get, set member val Timestamp = DateTimeOffset.MinValue with get, set member val Version = int64 (0) with get, set 

WrappedEvent is used like this:

let MapToSubtype subtype = match subtype with | CustomerRegistered registeredCustomer -> WrappedEvent<CustomerRegisteredEvent> registeredCustomer :> Events.IEvent | CustomerDeleted deletedCustomer -> WrappedEvent<CustomerDeletedEvent> deletedCustomer :> Events.IEvent 

The compiler throws an error for <'T> at WrappedEvent<'T>

This type parameter has been used in a way that constrains it to always be 'obj' This code is less generic than required by its annotations because the explicit type variable 'T' could not be generalized. It was constrained to be 'obj'. 

A warning is shown for Data at member val Data:

This construct causes code to be less generic than indicated by the type annotations. The type variable 'T has been constrained to be type 'obj'. 

How do I solve this?

Update:

If I'm implementing the interface like this interface Events.IEvent<'T> with (using the generic parameter), I get this error:

No implementation was given for 'Events.IEvent.get_Data() : obj'. Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'. 
6
  • Did you forget to specify the interface's generic parameter? Could there be a different interface also named IEvent, but not generic? That's a common pattern from the early days of .NET Commented Mar 22, 2021 at 20:19
  • @FyodorSoikin you mean like interface Events.IEvent<'T> with? Commented Mar 22, 2021 at 20:24
  • @FyodorSoikin I've added more information to the question Commented Mar 22, 2021 at 20:32
  • So you're not implementing IEvent<T> at all, right? Wasn't that the goal? Commented Mar 22, 2021 at 20:39
  • I've changed it to interface Events.IEvent<'T> with and now I get the error No implementation was given for 'Events.IEvent.get_Data() : obj'. Commented Mar 22, 2021 at 20:52

1 Answer 1

1

First, you're implementing two interfaces here, not one, - IEvent<T> and its base interface IEvent. As such, you need to add two interface ... with blocks - one for each:

type WrappedEvent<'T>(x: 'T) = interface Events.IEvent<'T> with member val Data = x with get interface Events.IEvent with member val Data = x with get member val DotNetTypeName = null with get, set member val EventType = null ... 

Second, when implementing the IEvent interface, note the type of its Data member: it's obj. So if you initialize that member with x, it follows that x must have type obj. And that's the source of your original error: x is used in such a way that will make it constrained to obj.

To fix this, you need to downcast x to obj before initializing Data with it:

 interface Events.IEvent with member val Data = x :> obj with get 

But wait! This will still not work. The problem is, member val declares not just a property, but also a backing field for it. And now you're declaring two different backing fields, both named Data, but of different types. (also, btw, you don't actually need separate backing fields, right? because you already have x)

So to get around that, make them properties without backing fields:

 interface Events.IEvent<'T> with member self.Data with get() = x interface Events.IEvent with member self.Data with get() = x :> obj ... 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, now everything works as expected.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.