I have been working on a list of records for some computations using a class that inherits from a List<> and implements some additional functions. Something like:
public class ComplexValue
{
public double value;
public string name;
private int type;
// More members here
}
public class ListOfComplexValues : List<ComplexValue>
{
public void UpdateValues(double parameter)
{
for (int i = 0; i < this.Count; i++)
{
this[i].value = SomeFunction(this[i].value, parameter);
}
}
}
It turns out that the computations I need to make, take one or more of those lists and generate combinations of them to produce new, much larger ones but for which I only need to keep the (double) value. Given the size of those new lists I had to simplify them to be just lists of double because of memory issue and speed. So I have a new class which also implements many of the functions that were implemented for the other. The code is the same, except that in one case I use this[i] and in the other this[i].value.
public class ListOfValues : List<double>
{
public void UpdateValues(double parameter)
{
for (int i = 0; i < this.Count; i++)
{
this[i] = SomeFunction(this[i], parameter);
}
}
}
Is there a way I could easily merge those two implementations, for instance ensuring that the ComplexValue class behaves like a double?
Unfortunately, it's not very clear from your question what it is you actually want to do. That is, in what way do you want "that the ComplexValue class behaves like a double" ? What would the code look like, in which the ComplexValue
class is used but behaves like a double
?
As you're aware I'm sure, you cannot inherit double
, because it's a value type. So polymorphism is not an option here, at least not on the value type itself. But if you are willing to take a step back and reevaluate what led you to the List<T>
-derived classes in the first place, perhaps there are options that would work for you.
In my experience, it's very unusual for inheriting a collection type to be the correct approach; only when the subclass is doing genuine collection -oriented things, and only collection-oriented things, would subclassing a collection type be appropriate. Otherwise, it usually makes more sense to put the non-collection-oriented operations into some other class that has a collection type (like the List<T>
object).
In any case (ie whether you compose or inherit), you could use some kind of accessor delegates to handle the disparity between collections of List<double>
and of List<ComplexValue>
.
For example (for the sake of clarity, I'm keeping the inherit approach here, even though IMHO composing is likely to be better):
class ListOfValues<T> : List<T>
{
private readonly Func<List<T>, int, double> _getter;
private readonly Action<List<T>, int, double> _setter;
public ListOfTValues(
Func<List<T>, int, double> getter, Action<List<T>, int, double> setter)
{
_getter = getter;
_setter = setter;
}
public void UpdateValues(double parameter)
{
for (int i = 0; i < this.Count; i++)
{
_setter(this, i, SomeFunction(_getter(this, i), parameter));
}
}
}
Then you could create your list object like this:
ListOfValues<double> doubleList = new ListOfValues<double>(
(list, i) => list[i], (list, i, value) => list[i] = value);
ListOfValues<ComplexValue> doubleList = new ListOfValues<ComplexValue>(
(list, i) => list[i].value, (list, i, value) => list[i].value = value);
Another alternative would be to do something similar to the above — ie provide accessor methods to map the collection type to the actual computational code — but to provide them as virtual method overrides rather than delegates:
abstract class ListOfValues<T> : List<T>
{
protected abstract double GetItemValue(int i);
protected abstract void SetItemValue(int i, double value);
public void UpdateValues(double parameter)
{
for (int i = 0; i < this.Count; i++)
{
SetItemValue(, i, SomeFunction(GetItemValue(i), parameter));
}
}
}
class ListOfDouble : ListOfValues<double>
{
protected override double GetItemValue(int i)
{
return this[i];
}
protected override void SetItemValue(int i, double value)
{
this[i] = value;
}
}
class ListOfComplexValue : ListOfValues<ComplexValue>
{
protected override double GetItemValue(int i)
{
return this[i].value;
}
protected override void SetItemValue(int i, double value)
{
this[i].value = value;
}
}
Note that all of the above could be implemented without inheriting the List<T>
type. You can put the computation logic into a class that simply contains an instance of List<T>
instead. Finally, note that all of the above still works even if you follow the advice that Jon provided in his first comment to your question (advice that I think is good and worth following).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.