-2

I have the following method signature:

Party cloneParty(bool useGivenParams, int i_PartyId, PartyRole i_PartyRole, DeletedState i_Deleted)

and also a member collection of existing parties called m_PartiesById.

Is there an elegant way to write the method to achieve the following behavior:

  1. I want to be able to call the method only with the ID, in which case I want to get back a copy of the party (if that ID exists in the collection) unchanged. For example:

    Party identicalClone = cloneParty(123);
    
  2. I want to be able to call the method only with the ID and the argument(s) that I want to change in the clone I'm creating. For example:

    Party slightlyChangedClone = cloneParty(123, PartyRole.To);
    
River
  • 8,585
  • 14
  • 54
  • 67
felisimo
  • 198
  • 14
  • what is your language – Basil Battikhi Sep 06 '17 at 14:19
  • Sorry, added an edit. I am writing in C# – felisimo Sep 06 '17 at 14:29
  • Can you explain what you're trying to achieve by doing this? "Make it elegant", but who's the consumer? Do you need to guarantee that the invoker can't alter the existing values, or are they required to be responsible for the integrity of the original data? Will the data be cloned locally, or remotely? Will there need to be logic that takes place per property changed, such as is the case in Entity Framework change tracker? Please be more specific. "I feel bad about writing this code this way" is the start of a conversation... not a question that can be answered directly. – cwharris Dec 24 '17 at 20:58

2 Answers2

1

Why not just make the optional parameters default to null, and only change the values that aren't null:

Party cloneParty(int i_Id, PartyRole i_PartyRole = null, DeletedState i_Deleted = null){
    Party clone = #clone party from i_Id here
    clone.PartyRole = i_PartyRole ?? clone.PartyRole;
    clone.DeletedState = i_Deleted ?? clone.DeletedState;
    return clone;
}

It looks like PartyRole might be an enum, in which case you'd need PartyRole? i_PartyRole = null instead (note the added question mark).

You can also do if(i_PartyRole != null) clone.PartyRole = i_PartyRole instead of ?? statements if you prefer.

Do you really need the method?

As I discussed with Christopher, you might be better off just doing this manually, by cloning the Party and setting any properties as you need.

River
  • 8,585
  • 14
  • 54
  • 67
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/161911/discussion-between-river-and-christopher-harris). – River Dec 24 '17 at 21:28
1

One way to do this is with Expressions, allthough I believe that's complete overkill for something like this. Your method signature would look like the following:

Party CloneParty(int id, Expression<Func<Party>> valueMergeSelector);

The invocation would look as follows:

var clonedParty = CloneParty(5, () => new Party { Role = PartyRole.Whatever });

The implementation of this method would be unnecessarily complicated and involve compiling and executing the expression, storing the new Party's values, using a custom subclass of ExpressionVisitor designed to figure out which of that Party's properties were assigned, create a bag to store those properties, clone the original object, and then loop over the bag to assign the new Party's applicable values (as indicated by the bag's index) to the clone's properties, and return the clone with the newly assigned values.

This would ensure that any value on Party could be set without having to worry about optional parameters, or wrapping each of the properties values in some sort of "IsARealValue" class, such as with Nullable.

The only real use case for something like this is a public-facing API which would require you (the api-developer) to know what values are being assigned at run time, for the purpose of query construction, etc.

Edit

After talking with @River, it sounds like trying to make a clone method with the ability to assign new values is, in most cases, just over-engineering a very simple existing pattern:

var clone = GetClone(5);
clone.Role = PartyRole.Whatever;

Unless there's a reason this wouldn't work, it's probably the most elegant solution, seeing as how no-body has to figure out how to use it.

cwharris
  • 17,835
  • 4
  • 44
  • 64