Couple related types together to control use in code using generics












1















I am trying to limit the use of types by chaining the aggregate IAggregate, the aggregate event IDomainEvent, and Identity together with generics, I have snipped the below code to give context of the issue of what I have got so far.



I have the following interfaces:



public abstract class Identity<T>
{
protected abstract string GetIdentity();
}

public interface IAggregate<T>
{
Identity<T> Identity { get; }
}

public interface IDomainEvent<TIdentity,TIdentity>
where T : Identity<TIdentity>
{
TIdentity Id { get; }
}


I implement with the below:



public class TestUserId : Identity<TestUser>
{
public TestUserId(string name) { Name = name; }
readonly public string Name;
protected override string GetIdentity() => Name.ToLowerInvariant();
}

public class TestUser : IAggregate<TestUser>
{
public TestUser(TestUserId id)
{
Id = id;
var ev = new TestUserCreated()
}
public TestUserId Id { get; }
public Identity<TestUser> Identity => Id;
}

public class TestUserCreated : IDomainEvent<TestUserId, TestUser>
{
public TestUserCreated() { }
public TestUserId Id => throw new NotImplementedException();
}


Then in the command handler, for this event to be used (and for me to be able to obtain the TestUserId which should be member of the domainEvent object).



public interface IDomainEventHandler<TEvent>
{
void Handle(TEvent domainEvent, bool isReplay);
}


That gives me the code:



public class TesterHandler : IDomainEventHandler<TestUser, TestUserCreated>
{
public void Handle(TestUserCreated domainEvent, bool isReplay)
{
// can access the ID (of type TestUserId)
var testUserId = domainEvent.Id;
}
}


So the above TesterHandler is fine exactly how i would want - however the compiler is failing on class TestUserCreated : IDomainEvent<TestUserId, TestUser> with The type TestUserId' cannot be used as type parameter 'TIdentity' in the generic type or method 'IDomainEvent<TIdentity, Type>'. There is no implicit reference conversion from 'TestUserId' to 'Identity<TestUser>'.



What I want is to couple (without OO inheritance) the event to the aggregate, so that it is tied to a specific aggregate type (i.e. specific events are tied to a specific entity, and the entity ID is part of the event type as a field), I want to try and make it impossible to code event handlers for unrelated aggregates.



I am trying to implement but the compiler complains of boxing and implicit casting errors (depending on what i try/guess), in short I am unsure how to code the above.










share|improve this question




















  • 1





    Beyond anything else, you would be strongly advised to never use the name of a well-known type (such as Type) as the name of a generic parameter. I guarantee it will lead to confusion. Best practice is to name all generic parameters with a prefix of T similar to how interfaces are named prefixed with I.

    – Kirk Woll
    Jan 1 at 19:45








  • 1





    Also, can you explain what has proven deficient with your approach? Are you receiving errors? What exactly is not working?

    – Kirk Woll
    Jan 1 at 19:48













  • well.. this usage and notion of aggregate is a bit of a cause of confusion to me. Rather, it has been for awhile - as It doesn't really fit the many to one operation I have. An aggregate is basically a function (event handler in your premise) that you apply to a collection (sequence of events in your premise, I think) with some sort of singular projection coming out of it (perhaps even a singular event).

    – Brett Caswell
    Jan 1 at 21:03






  • 1





    A few things about your code dont make sense. 1. Why does Identity have a generic parameter but not use it? 2. IDomainEvent specifies two generic parameters (named the same, must be a mistake?) and then has a generic constraint on a generic parameter which doesnt exist (T) 3. IDomainEventHandler specifies 1 generic parameter but is implemented with 2!

    – Jamiec
    Jan 2 at 8:46








  • 1





    Or, to put it another way, here is a Minimal, Complete, and Verifiable example of your code edited to actually compile and run: rextester.com/XABFSP58589 - what is wrong with this code that doesnt do what you expect?

    – Jamiec
    Jan 2 at 10:09


















1















I am trying to limit the use of types by chaining the aggregate IAggregate, the aggregate event IDomainEvent, and Identity together with generics, I have snipped the below code to give context of the issue of what I have got so far.



I have the following interfaces:



public abstract class Identity<T>
{
protected abstract string GetIdentity();
}

public interface IAggregate<T>
{
Identity<T> Identity { get; }
}

public interface IDomainEvent<TIdentity,TIdentity>
where T : Identity<TIdentity>
{
TIdentity Id { get; }
}


I implement with the below:



public class TestUserId : Identity<TestUser>
{
public TestUserId(string name) { Name = name; }
readonly public string Name;
protected override string GetIdentity() => Name.ToLowerInvariant();
}

public class TestUser : IAggregate<TestUser>
{
public TestUser(TestUserId id)
{
Id = id;
var ev = new TestUserCreated()
}
public TestUserId Id { get; }
public Identity<TestUser> Identity => Id;
}

public class TestUserCreated : IDomainEvent<TestUserId, TestUser>
{
public TestUserCreated() { }
public TestUserId Id => throw new NotImplementedException();
}


Then in the command handler, for this event to be used (and for me to be able to obtain the TestUserId which should be member of the domainEvent object).



public interface IDomainEventHandler<TEvent>
{
void Handle(TEvent domainEvent, bool isReplay);
}


That gives me the code:



public class TesterHandler : IDomainEventHandler<TestUser, TestUserCreated>
{
public void Handle(TestUserCreated domainEvent, bool isReplay)
{
// can access the ID (of type TestUserId)
var testUserId = domainEvent.Id;
}
}


So the above TesterHandler is fine exactly how i would want - however the compiler is failing on class TestUserCreated : IDomainEvent<TestUserId, TestUser> with The type TestUserId' cannot be used as type parameter 'TIdentity' in the generic type or method 'IDomainEvent<TIdentity, Type>'. There is no implicit reference conversion from 'TestUserId' to 'Identity<TestUser>'.



What I want is to couple (without OO inheritance) the event to the aggregate, so that it is tied to a specific aggregate type (i.e. specific events are tied to a specific entity, and the entity ID is part of the event type as a field), I want to try and make it impossible to code event handlers for unrelated aggregates.



I am trying to implement but the compiler complains of boxing and implicit casting errors (depending on what i try/guess), in short I am unsure how to code the above.










share|improve this question




















  • 1





    Beyond anything else, you would be strongly advised to never use the name of a well-known type (such as Type) as the name of a generic parameter. I guarantee it will lead to confusion. Best practice is to name all generic parameters with a prefix of T similar to how interfaces are named prefixed with I.

    – Kirk Woll
    Jan 1 at 19:45








  • 1





    Also, can you explain what has proven deficient with your approach? Are you receiving errors? What exactly is not working?

    – Kirk Woll
    Jan 1 at 19:48













  • well.. this usage and notion of aggregate is a bit of a cause of confusion to me. Rather, it has been for awhile - as It doesn't really fit the many to one operation I have. An aggregate is basically a function (event handler in your premise) that you apply to a collection (sequence of events in your premise, I think) with some sort of singular projection coming out of it (perhaps even a singular event).

    – Brett Caswell
    Jan 1 at 21:03






  • 1





    A few things about your code dont make sense. 1. Why does Identity have a generic parameter but not use it? 2. IDomainEvent specifies two generic parameters (named the same, must be a mistake?) and then has a generic constraint on a generic parameter which doesnt exist (T) 3. IDomainEventHandler specifies 1 generic parameter but is implemented with 2!

    – Jamiec
    Jan 2 at 8:46








  • 1





    Or, to put it another way, here is a Minimal, Complete, and Verifiable example of your code edited to actually compile and run: rextester.com/XABFSP58589 - what is wrong with this code that doesnt do what you expect?

    – Jamiec
    Jan 2 at 10:09
















1












1








1


2






I am trying to limit the use of types by chaining the aggregate IAggregate, the aggregate event IDomainEvent, and Identity together with generics, I have snipped the below code to give context of the issue of what I have got so far.



I have the following interfaces:



public abstract class Identity<T>
{
protected abstract string GetIdentity();
}

public interface IAggregate<T>
{
Identity<T> Identity { get; }
}

public interface IDomainEvent<TIdentity,TIdentity>
where T : Identity<TIdentity>
{
TIdentity Id { get; }
}


I implement with the below:



public class TestUserId : Identity<TestUser>
{
public TestUserId(string name) { Name = name; }
readonly public string Name;
protected override string GetIdentity() => Name.ToLowerInvariant();
}

public class TestUser : IAggregate<TestUser>
{
public TestUser(TestUserId id)
{
Id = id;
var ev = new TestUserCreated()
}
public TestUserId Id { get; }
public Identity<TestUser> Identity => Id;
}

public class TestUserCreated : IDomainEvent<TestUserId, TestUser>
{
public TestUserCreated() { }
public TestUserId Id => throw new NotImplementedException();
}


Then in the command handler, for this event to be used (and for me to be able to obtain the TestUserId which should be member of the domainEvent object).



public interface IDomainEventHandler<TEvent>
{
void Handle(TEvent domainEvent, bool isReplay);
}


That gives me the code:



public class TesterHandler : IDomainEventHandler<TestUser, TestUserCreated>
{
public void Handle(TestUserCreated domainEvent, bool isReplay)
{
// can access the ID (of type TestUserId)
var testUserId = domainEvent.Id;
}
}


So the above TesterHandler is fine exactly how i would want - however the compiler is failing on class TestUserCreated : IDomainEvent<TestUserId, TestUser> with The type TestUserId' cannot be used as type parameter 'TIdentity' in the generic type or method 'IDomainEvent<TIdentity, Type>'. There is no implicit reference conversion from 'TestUserId' to 'Identity<TestUser>'.



What I want is to couple (without OO inheritance) the event to the aggregate, so that it is tied to a specific aggregate type (i.e. specific events are tied to a specific entity, and the entity ID is part of the event type as a field), I want to try and make it impossible to code event handlers for unrelated aggregates.



I am trying to implement but the compiler complains of boxing and implicit casting errors (depending on what i try/guess), in short I am unsure how to code the above.










share|improve this question
















I am trying to limit the use of types by chaining the aggregate IAggregate, the aggregate event IDomainEvent, and Identity together with generics, I have snipped the below code to give context of the issue of what I have got so far.



I have the following interfaces:



public abstract class Identity<T>
{
protected abstract string GetIdentity();
}

public interface IAggregate<T>
{
Identity<T> Identity { get; }
}

public interface IDomainEvent<TIdentity,TIdentity>
where T : Identity<TIdentity>
{
TIdentity Id { get; }
}


I implement with the below:



public class TestUserId : Identity<TestUser>
{
public TestUserId(string name) { Name = name; }
readonly public string Name;
protected override string GetIdentity() => Name.ToLowerInvariant();
}

public class TestUser : IAggregate<TestUser>
{
public TestUser(TestUserId id)
{
Id = id;
var ev = new TestUserCreated()
}
public TestUserId Id { get; }
public Identity<TestUser> Identity => Id;
}

public class TestUserCreated : IDomainEvent<TestUserId, TestUser>
{
public TestUserCreated() { }
public TestUserId Id => throw new NotImplementedException();
}


Then in the command handler, for this event to be used (and for me to be able to obtain the TestUserId which should be member of the domainEvent object).



public interface IDomainEventHandler<TEvent>
{
void Handle(TEvent domainEvent, bool isReplay);
}


That gives me the code:



public class TesterHandler : IDomainEventHandler<TestUser, TestUserCreated>
{
public void Handle(TestUserCreated domainEvent, bool isReplay)
{
// can access the ID (of type TestUserId)
var testUserId = domainEvent.Id;
}
}


So the above TesterHandler is fine exactly how i would want - however the compiler is failing on class TestUserCreated : IDomainEvent<TestUserId, TestUser> with The type TestUserId' cannot be used as type parameter 'TIdentity' in the generic type or method 'IDomainEvent<TIdentity, Type>'. There is no implicit reference conversion from 'TestUserId' to 'Identity<TestUser>'.



What I want is to couple (without OO inheritance) the event to the aggregate, so that it is tied to a specific aggregate type (i.e. specific events are tied to a specific entity, and the entity ID is part of the event type as a field), I want to try and make it impossible to code event handlers for unrelated aggregates.



I am trying to implement but the compiler complains of boxing and implicit casting errors (depending on what i try/guess), in short I am unsure how to code the above.







c# generics






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 2 at 18:47







g18c

















asked Jan 1 at 19:39









g18cg18c

53562574




53562574








  • 1





    Beyond anything else, you would be strongly advised to never use the name of a well-known type (such as Type) as the name of a generic parameter. I guarantee it will lead to confusion. Best practice is to name all generic parameters with a prefix of T similar to how interfaces are named prefixed with I.

    – Kirk Woll
    Jan 1 at 19:45








  • 1





    Also, can you explain what has proven deficient with your approach? Are you receiving errors? What exactly is not working?

    – Kirk Woll
    Jan 1 at 19:48













  • well.. this usage and notion of aggregate is a bit of a cause of confusion to me. Rather, it has been for awhile - as It doesn't really fit the many to one operation I have. An aggregate is basically a function (event handler in your premise) that you apply to a collection (sequence of events in your premise, I think) with some sort of singular projection coming out of it (perhaps even a singular event).

    – Brett Caswell
    Jan 1 at 21:03






  • 1





    A few things about your code dont make sense. 1. Why does Identity have a generic parameter but not use it? 2. IDomainEvent specifies two generic parameters (named the same, must be a mistake?) and then has a generic constraint on a generic parameter which doesnt exist (T) 3. IDomainEventHandler specifies 1 generic parameter but is implemented with 2!

    – Jamiec
    Jan 2 at 8:46








  • 1





    Or, to put it another way, here is a Minimal, Complete, and Verifiable example of your code edited to actually compile and run: rextester.com/XABFSP58589 - what is wrong with this code that doesnt do what you expect?

    – Jamiec
    Jan 2 at 10:09
















  • 1





    Beyond anything else, you would be strongly advised to never use the name of a well-known type (such as Type) as the name of a generic parameter. I guarantee it will lead to confusion. Best practice is to name all generic parameters with a prefix of T similar to how interfaces are named prefixed with I.

    – Kirk Woll
    Jan 1 at 19:45








  • 1





    Also, can you explain what has proven deficient with your approach? Are you receiving errors? What exactly is not working?

    – Kirk Woll
    Jan 1 at 19:48













  • well.. this usage and notion of aggregate is a bit of a cause of confusion to me. Rather, it has been for awhile - as It doesn't really fit the many to one operation I have. An aggregate is basically a function (event handler in your premise) that you apply to a collection (sequence of events in your premise, I think) with some sort of singular projection coming out of it (perhaps even a singular event).

    – Brett Caswell
    Jan 1 at 21:03






  • 1





    A few things about your code dont make sense. 1. Why does Identity have a generic parameter but not use it? 2. IDomainEvent specifies two generic parameters (named the same, must be a mistake?) and then has a generic constraint on a generic parameter which doesnt exist (T) 3. IDomainEventHandler specifies 1 generic parameter but is implemented with 2!

    – Jamiec
    Jan 2 at 8:46








  • 1





    Or, to put it another way, here is a Minimal, Complete, and Verifiable example of your code edited to actually compile and run: rextester.com/XABFSP58589 - what is wrong with this code that doesnt do what you expect?

    – Jamiec
    Jan 2 at 10:09










1




1





Beyond anything else, you would be strongly advised to never use the name of a well-known type (such as Type) as the name of a generic parameter. I guarantee it will lead to confusion. Best practice is to name all generic parameters with a prefix of T similar to how interfaces are named prefixed with I.

– Kirk Woll
Jan 1 at 19:45







Beyond anything else, you would be strongly advised to never use the name of a well-known type (such as Type) as the name of a generic parameter. I guarantee it will lead to confusion. Best practice is to name all generic parameters with a prefix of T similar to how interfaces are named prefixed with I.

– Kirk Woll
Jan 1 at 19:45






1




1





Also, can you explain what has proven deficient with your approach? Are you receiving errors? What exactly is not working?

– Kirk Woll
Jan 1 at 19:48







Also, can you explain what has proven deficient with your approach? Are you receiving errors? What exactly is not working?

– Kirk Woll
Jan 1 at 19:48















well.. this usage and notion of aggregate is a bit of a cause of confusion to me. Rather, it has been for awhile - as It doesn't really fit the many to one operation I have. An aggregate is basically a function (event handler in your premise) that you apply to a collection (sequence of events in your premise, I think) with some sort of singular projection coming out of it (perhaps even a singular event).

– Brett Caswell
Jan 1 at 21:03





well.. this usage and notion of aggregate is a bit of a cause of confusion to me. Rather, it has been for awhile - as It doesn't really fit the many to one operation I have. An aggregate is basically a function (event handler in your premise) that you apply to a collection (sequence of events in your premise, I think) with some sort of singular projection coming out of it (perhaps even a singular event).

– Brett Caswell
Jan 1 at 21:03




1




1





A few things about your code dont make sense. 1. Why does Identity have a generic parameter but not use it? 2. IDomainEvent specifies two generic parameters (named the same, must be a mistake?) and then has a generic constraint on a generic parameter which doesnt exist (T) 3. IDomainEventHandler specifies 1 generic parameter but is implemented with 2!

– Jamiec
Jan 2 at 8:46







A few things about your code dont make sense. 1. Why does Identity have a generic parameter but not use it? 2. IDomainEvent specifies two generic parameters (named the same, must be a mistake?) and then has a generic constraint on a generic parameter which doesnt exist (T) 3. IDomainEventHandler specifies 1 generic parameter but is implemented with 2!

– Jamiec
Jan 2 at 8:46






1




1





Or, to put it another way, here is a Minimal, Complete, and Verifiable example of your code edited to actually compile and run: rextester.com/XABFSP58589 - what is wrong with this code that doesnt do what you expect?

– Jamiec
Jan 2 at 10:09







Or, to put it another way, here is a Minimal, Complete, and Verifiable example of your code edited to actually compile and run: rextester.com/XABFSP58589 - what is wrong with this code that doesnt do what you expect?

– Jamiec
Jan 2 at 10:09














1 Answer
1






active

oldest

votes


















1














Given I was unable to create running code as per comments requested (hence the reason for the post) and general complexity, I decided using generics in this way was a bad idea with rationale below.



I currently have code which calls the handler as follows (and this is working fine) passing in the sourceIdentity external to the domainEvent object:



public interface IDomainEventHandler<TIdentity, TEvent>
where TIdentity : IIdentity
where TEvent : IDomainEvent
{
void Handle(TIdentity sourceIdentity, TEvent domainEvent, bool isReplay);
}


I am passing in the aggregate ID external to the IDomainEvent object (and this is desired to keep the events, from an event sourcing perspective, as simple as possible as simple POCO objects without inheritance or involving any framework).



The reason for the question was I just wanted to explore all options with generics (so the domainEvent object could have an interface that would give an ID field) but it started to get complicated quickly, specifically additional template parameters would be required since we are inferring relationships via templates, rather than OO relationships.



Without OO, the relationship would need to be defined somewhere by adding additional types to templates to tie them together interface IDomainEvent<TIdentity,TAggregate,TEvent> and interface IDomainEventHandler<TIdentity, TAggregate, TEvent>, in this case OO inheritance would be preferred and result in way less code.



All this was done to give an interface to obtain the ID, however as if an ID is really needed it can be incorporated in the event as a normal field (without the need for complex OO relationships or templates).



public interface IDomainEvent
{
DateTime OccurredOn { get; set; }
Guid MessageId { get; set; }
}

public class TestUserCreated : IDomainEvent
{
// id can be accessed by whatever needs it by being
// defined explicity within the domain event POCO
// without needing any base class or framework.
public readonly TestUserId Id;

public readonly string Name;

public TestUserCreated(TestUserId id, string name)
{
Id = id;
Name = name;
}
}





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53998389%2fcouple-related-types-together-to-control-use-in-code-using-generics%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    Given I was unable to create running code as per comments requested (hence the reason for the post) and general complexity, I decided using generics in this way was a bad idea with rationale below.



    I currently have code which calls the handler as follows (and this is working fine) passing in the sourceIdentity external to the domainEvent object:



    public interface IDomainEventHandler<TIdentity, TEvent>
    where TIdentity : IIdentity
    where TEvent : IDomainEvent
    {
    void Handle(TIdentity sourceIdentity, TEvent domainEvent, bool isReplay);
    }


    I am passing in the aggregate ID external to the IDomainEvent object (and this is desired to keep the events, from an event sourcing perspective, as simple as possible as simple POCO objects without inheritance or involving any framework).



    The reason for the question was I just wanted to explore all options with generics (so the domainEvent object could have an interface that would give an ID field) but it started to get complicated quickly, specifically additional template parameters would be required since we are inferring relationships via templates, rather than OO relationships.



    Without OO, the relationship would need to be defined somewhere by adding additional types to templates to tie them together interface IDomainEvent<TIdentity,TAggregate,TEvent> and interface IDomainEventHandler<TIdentity, TAggregate, TEvent>, in this case OO inheritance would be preferred and result in way less code.



    All this was done to give an interface to obtain the ID, however as if an ID is really needed it can be incorporated in the event as a normal field (without the need for complex OO relationships or templates).



    public interface IDomainEvent
    {
    DateTime OccurredOn { get; set; }
    Guid MessageId { get; set; }
    }

    public class TestUserCreated : IDomainEvent
    {
    // id can be accessed by whatever needs it by being
    // defined explicity within the domain event POCO
    // without needing any base class or framework.
    public readonly TestUserId Id;

    public readonly string Name;

    public TestUserCreated(TestUserId id, string name)
    {
    Id = id;
    Name = name;
    }
    }





    share|improve this answer




























      1














      Given I was unable to create running code as per comments requested (hence the reason for the post) and general complexity, I decided using generics in this way was a bad idea with rationale below.



      I currently have code which calls the handler as follows (and this is working fine) passing in the sourceIdentity external to the domainEvent object:



      public interface IDomainEventHandler<TIdentity, TEvent>
      where TIdentity : IIdentity
      where TEvent : IDomainEvent
      {
      void Handle(TIdentity sourceIdentity, TEvent domainEvent, bool isReplay);
      }


      I am passing in the aggregate ID external to the IDomainEvent object (and this is desired to keep the events, from an event sourcing perspective, as simple as possible as simple POCO objects without inheritance or involving any framework).



      The reason for the question was I just wanted to explore all options with generics (so the domainEvent object could have an interface that would give an ID field) but it started to get complicated quickly, specifically additional template parameters would be required since we are inferring relationships via templates, rather than OO relationships.



      Without OO, the relationship would need to be defined somewhere by adding additional types to templates to tie them together interface IDomainEvent<TIdentity,TAggregate,TEvent> and interface IDomainEventHandler<TIdentity, TAggregate, TEvent>, in this case OO inheritance would be preferred and result in way less code.



      All this was done to give an interface to obtain the ID, however as if an ID is really needed it can be incorporated in the event as a normal field (without the need for complex OO relationships or templates).



      public interface IDomainEvent
      {
      DateTime OccurredOn { get; set; }
      Guid MessageId { get; set; }
      }

      public class TestUserCreated : IDomainEvent
      {
      // id can be accessed by whatever needs it by being
      // defined explicity within the domain event POCO
      // without needing any base class or framework.
      public readonly TestUserId Id;

      public readonly string Name;

      public TestUserCreated(TestUserId id, string name)
      {
      Id = id;
      Name = name;
      }
      }





      share|improve this answer


























        1












        1








        1







        Given I was unable to create running code as per comments requested (hence the reason for the post) and general complexity, I decided using generics in this way was a bad idea with rationale below.



        I currently have code which calls the handler as follows (and this is working fine) passing in the sourceIdentity external to the domainEvent object:



        public interface IDomainEventHandler<TIdentity, TEvent>
        where TIdentity : IIdentity
        where TEvent : IDomainEvent
        {
        void Handle(TIdentity sourceIdentity, TEvent domainEvent, bool isReplay);
        }


        I am passing in the aggregate ID external to the IDomainEvent object (and this is desired to keep the events, from an event sourcing perspective, as simple as possible as simple POCO objects without inheritance or involving any framework).



        The reason for the question was I just wanted to explore all options with generics (so the domainEvent object could have an interface that would give an ID field) but it started to get complicated quickly, specifically additional template parameters would be required since we are inferring relationships via templates, rather than OO relationships.



        Without OO, the relationship would need to be defined somewhere by adding additional types to templates to tie them together interface IDomainEvent<TIdentity,TAggregate,TEvent> and interface IDomainEventHandler<TIdentity, TAggregate, TEvent>, in this case OO inheritance would be preferred and result in way less code.



        All this was done to give an interface to obtain the ID, however as if an ID is really needed it can be incorporated in the event as a normal field (without the need for complex OO relationships or templates).



        public interface IDomainEvent
        {
        DateTime OccurredOn { get; set; }
        Guid MessageId { get; set; }
        }

        public class TestUserCreated : IDomainEvent
        {
        // id can be accessed by whatever needs it by being
        // defined explicity within the domain event POCO
        // without needing any base class or framework.
        public readonly TestUserId Id;

        public readonly string Name;

        public TestUserCreated(TestUserId id, string name)
        {
        Id = id;
        Name = name;
        }
        }





        share|improve this answer













        Given I was unable to create running code as per comments requested (hence the reason for the post) and general complexity, I decided using generics in this way was a bad idea with rationale below.



        I currently have code which calls the handler as follows (and this is working fine) passing in the sourceIdentity external to the domainEvent object:



        public interface IDomainEventHandler<TIdentity, TEvent>
        where TIdentity : IIdentity
        where TEvent : IDomainEvent
        {
        void Handle(TIdentity sourceIdentity, TEvent domainEvent, bool isReplay);
        }


        I am passing in the aggregate ID external to the IDomainEvent object (and this is desired to keep the events, from an event sourcing perspective, as simple as possible as simple POCO objects without inheritance or involving any framework).



        The reason for the question was I just wanted to explore all options with generics (so the domainEvent object could have an interface that would give an ID field) but it started to get complicated quickly, specifically additional template parameters would be required since we are inferring relationships via templates, rather than OO relationships.



        Without OO, the relationship would need to be defined somewhere by adding additional types to templates to tie them together interface IDomainEvent<TIdentity,TAggregate,TEvent> and interface IDomainEventHandler<TIdentity, TAggregate, TEvent>, in this case OO inheritance would be preferred and result in way less code.



        All this was done to give an interface to obtain the ID, however as if an ID is really needed it can be incorporated in the event as a normal field (without the need for complex OO relationships or templates).



        public interface IDomainEvent
        {
        DateTime OccurredOn { get; set; }
        Guid MessageId { get; set; }
        }

        public class TestUserCreated : IDomainEvent
        {
        // id can be accessed by whatever needs it by being
        // defined explicity within the domain event POCO
        // without needing any base class or framework.
        public readonly TestUserId Id;

        public readonly string Name;

        public TestUserCreated(TestUserId id, string name)
        {
        Id = id;
        Name = name;
        }
        }






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 2 at 18:57









        g18cg18c

        53562574




        53562574
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53998389%2fcouple-related-types-together-to-control-use-in-code-using-generics%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            MongoDB - Not Authorized To Execute Command

            Npm cannot find a required file even through it is in the searched directory

            How to fix TextFormField cause rebuild widget in Flutter