How to implement the copy method of a universal class decorator?

Imagine you have a common interface that defines a common value and a copy constructor like this (replacing ICloneable):

// T: type of value to hold, TU: type of the class itself interface ICopyable<T,TU> where TU: ICopyable<T,TU> { T Value { get; set; } TU Copy(); } 

This can be implemented using a boolean value, for example:

 class BooleanHolder : ICopyable<Boolean, BooleanHolder> { public BooleanHolder Copy() { return new BooleanHolder(){ Value = Value }; } } 

Now the question is: how would you define a decorator class that contains another ICopyable? My broken idea:

 class DecoratingHolder<T,TU> : ICopyable<ICopyable<T,TU>, DecoratingHolder<T,TU>> { public DecoratingHolder<T,TU> Copy { // won't compile as Value is of type T and not of type ICopyable<T,TU> // as I expected - why is that? return new DecoratingHolder<T,TU>(){ Value = Value.Copy }; } } 

Note that I called Copy to also copy a value of type ICopyable<T,TU> , this is intended to provide deep copies.

So what do I need to change to make this structure work?

+4
source share
2 answers

You just need to add a restriction. You define that ICopyable<T, TU> where TU : ICopyable<T, TU> , but in your DecoratingHolder , you never explicitly limit TU as such to the DecoratingHolder .

In particular, I think this part of the line:

 class DecoratingHolder<T,TU> : ***ICopyable<ICopyable<T,TU>*** 

This is causing a problem. You define the type of ICopyable<T,TU> , but TU not limited to ICopyable<T, TU> . (one might conclude that from the rest of the class / inheritance declaration, but the compiler does not). When you add a constraint, the compiler knows that Value is a compatible type of ICopyable<T,TU> .

This compiles for me (it was necessary to fix some other minor things with the provided pseudocode):

 class DecoratingHolder<T,TU> : ICopyable<ICopyable<T,TU>, DecoratingHolder<T,TU>> where TU : ICopyable<T,TU> { public ICopyable<T,TU> Value { get; set; } public DecoratingHolder<T,TU> Copy() { return new DecoratingHolder<T, TU>(){ Value = Value }; } } 

EDIT: In retrospect, do you even need a restriction on ICopyable ? It seems that you are not doing much, as you already generally define the outgoing type. If you do not have the code elsewhere, it depends on the fact that for some reason it returns ICopyable<T, TU> (it would essentially be one or the other, since it would return a strongly typed TU or BooleanHolder or DecoratingHolder ) , and then thought about dumping it.

 interface ICopyable<T,TU> { T Value { get; set; } TU Copy(); } class BooleanHolder : ICopyable<Boolean, BooleanHolder> { public bool Value { get; set; } public BooleanHolder Copy() { return new BooleanHolder(){ Value = Value }; } } class DecoratingHolder<T,TU> : ICopyable<ICopyable<T,TU>, DecoratingHolder<T,TU>> { public ICopyable<T,TU> Value { get; set; } public DecoratingHolder<T,TU> Copy() { return new DecoratingHolder<T, TU>(){ Value = Value }; } } 

EDIT: from your comment requiring a deep copy, save the restrictions (you'll need) and call Copy on Value (sorry, I must have missed this detail)

 class DecoratingHolder<T,TU> : ICopyable<ICopyable<T,TU>, DecoratingHolder<T,TU>> where TU : ICopyable<T,TU> { public ICopyable<T,TU> Value { get; set; } public DecoratingHolder<T,TU> Copy() { return new DecoratingHolder<T, TU>(){ Value = Value.Copy() }; } } 

Copy methods for any given class must be sure that they perform a deep copy. (I would suggest renaming Copy to DeepCopy if your infrastructure needs a deep copy of them and you don’t want the implementations to do small small things by accident)

+3
source

Casting worked for me:

  public DecoratingHolder<T, TU> Copy() { return new DecoratingHolder<T, TU>() { Value = (ICopyable<T, TU>)Value.Copy() }; } 

I assume that in this context the compiler does not go so far as to establish that TU and ICopyable<T, TU> are one and the same.

0
source

Source: https://habr.com/ru/post/1448106/


All Articles