I'm attempting to create a class, ExtendedDataFrame
, by inheriting DataFrame
from Microsoft.Data.Analysis
. The goal is to add a Name
property:
using Microsoft.Data.Analysis;
namespace Testing;
public class ExtendedDataFrame : DataFrame
{
public string Name { get; set; } = String.Empty;
public ExtendedDataFrame() : base() { }
public ExtendedDataFrame(string name) : base() => this.Name = name;
// Implement DataFrame's constructors:
public ExtendedDataFrame(string name, params DataFrameColumn[] columns) : base(columns)
{
this.Name = name;
}
public ExtendedDataFrame(string name, IEnumerable<DataFrameColumn> columns) : base(columns)
{
this.Name = name;
}
}
I can build an ExtendedDataFrame
:
public class Program
{
public static void Main(string[] args)
{
StringDataFrameColumn col = new("foo", 0);
col.Append("bar");
col.Append("baz");
ExtendedDataFrame edf = new("EDF", col);
...
}
}
But I have lost some functionality. DataFrame
has a Clone
method. I can use DataFrame
's Clone
method to create a DataFrame
:
// Note: Clone() returns a DataFrame object.
DataFrame df = edf.Clone();
However, if I cannot use DataFrame
's Clone
method to create an ExtendedDataFrame
:
ExtendedDataFrame edf2 = (ExtendedDataFrame)df.Clone();
This results in a System.InvalidCastException: Unable to cast object of type 'Microsoft.Data.Analysis.DataFrame' to type 'DataFrameExtension.ExtendedDataFrame'.
This make sense because Clone
is returning a DataFrame
object and edf2
is an ExtendedDataFrame
.
This brings me to my question. Other than Clone
, DataFrame
has other methdos (like Filter
) that return DataFrame
objects. Is there some way I can use those methods with ExtendedDataFrame
objects? Or, is there another means of adding a Name
property to DataFrame
?
CodePudding user response:
It sounds like you’re trying to augment the functionality of ‘DataFrame’ by adding additional stuff (like the Name property) and still use the underlying DataFrame logic like Clone() and Filter(), but you wish to also augment those methods to return instances of ‘ExtendedDataFrame’ instead of ‘DataFrame’.
You might consider a composition approach to give you greater control over your augmented class’s public API. The issue with plain inheritance is you can’t change the return type of Clone(), Filter(), etc. without some smelly workarounds.
Using composition, you take in as a parameter (or create internally) a DataFrame object, and wrap all functionality in your own custom functionality.
Like so:
public class ExtendedDataFrame {
private readonly DataFrame _dataFrame;
public string Name { get; set; }
public ExtendedDataFrame(string name) {
this.Name = name;
this._dataFrame = new DataFrame();
}
protected ExtendedDataFrame(string name, DataFrame dataFrame) {
this.Name = name;
this._dataFrame = dataFrame;
}
public ExtendedDataFrame Clone() {
return new ExtendedDataFrame(this.Name, this._dataFrame.Clone());
}
// Other methods here
}
The caveat is, any DataFrame methods you want to be exposed on your augmented data frame class, you need to manually create methods in your class that call the method on the underlying data frame.