1

I have a structed called ValueFrequency which starts its life as a struct where you (for statistical reasons) could store a (double) value, and an (int) frequency (telling how many times this value occured in a set of data. E.g. if you had a list/array with the values: 1,1,1,2,2,3,4,4,4,4,4 it could be stored as a list/array of ValueFrequency in stead: (1,3),(2,2),(3,1),(4,5).

Anyway I found in stead of hardcoding my scruct to use double I could use a generic, so I could use it with outher data-types (e.g. a Point, when using it to store data from a 2-dimentional set of data).

Simplified version of the struct:

public struct ValueFrequency<T> : IComparable, ICloneable where T : IComparable
{
  public T value;
  public int Frequency;
}

My problem is I want to use this struct with both structs/classes supporting ICloneable and ValueTypes like double. How would I write a copy-constructor (copying its fields from another ValueFrequncy), where it will either simply assign the same value (if type is ValueType) or Clone if the struct/class supports IClonable:

public ValueFrequency(ValueFrequency<T> valueFrequency)
{
  if (typeof(T).IsValueType)
    this.Value = valueFrequency.Value;
  else if (T is supporting IClonable)  // pseudo-code ???
    this.Value = (T)valueFrequency.Value.Clone();
  else
    throw new Exception("T must be ValueType or IClonable") ;
  this.Frequency = valueFrequency.Frequency;
}

As you can see my problem is testing for if T is IClonable, and the actual cloning (typecasts T to IClonable to perform the cloneing).

3 Answers3

3

Do you care that the type implements ICloneable or just that the underlying object is an ICloneable?

else if (valueFrequency.Value is ICloneable) 
    this.Value = (T)((ICloneable)valueFrequency.Value).Clone();
D Stanley
  • 149,601
  • 11
  • 178
  • 240
2

You can use the IsAssignableFrom method like this:

 bool is_cloneable = typeof(ICloneable).IsAssignableFrom(typeof(T));

Or you could cast valueFrequency.Value as ICloneable and test if it is not null like this:

ICloneable value_as_cloneable = valueFrequency.Value as ICloneable;

if(value_as_cloneable != null)
    this.Value = (T)value_as_cloneable.Clone();
Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
0

Thanks to the both of you (Yacoub Massad and D Stanley), I ended up implementing both of your solutions. I decided on the following implementation of my (copy)Constructor (which implements the suggestions of D Stanley):

public ValueFrequency(ValueFrequency<T> valueFrequency)
{
    if (valueFrequency.Value is ICloneable)
        Value = (T)((ICloneable)valueFrequency.Value).Clone();
    else
        Value = valueFrequency.Value;
    _frequency = valueFrequency.Frequency;
}

Another method of this struct can take an IEnumerable of ValueFrequency (which holds a value (T) and a Frequency (int)) and "unpack" it into a List of values(T), where each value is repeated as many times as the Frequency (this method implements the suggestions of Yacoub Massad):

public static List<T> ListOfValueFrequencyToList(IEnumerable<ValueFrequency<T>> valueFrequencyList)
{
    bool isCloneable = typeof(ICloneable).IsAssignableFrom(typeof(T));
    List<T> result = new List<T>();
    foreach (ValueFrequency<T> vf in valueFrequencyList)
    {
        for (int i = 0; i < vf.Frequency; i++)
        {
            if (isCloneable)
                result.Add((T)((ICloneable)vf.Value).Clone());
            else
                result.Add(vf.Value);
        }
    }
    return result;
}