简体   繁体   中英

C#: Shared struct fields and inheritance

Now I know that C# doesn't support inheritance of structs for a number of reasons. I was wondering however, if it is still possible to implement some form of hierarchy for data types such that a function can rely on a variable of type B or type C having field x because they both inherit from type A.

More specific: I have two structs that have a value field and coordinates (2D and 3D)

public struct BarDataPoint
{
    public TwoTuple<float> coords { get; }
    public float value { get; }
    public BarDataPoint(TwoTuple<float> coords, float value)
    {
        this.coords = coords;
        this.value = value;
    }
}

public struct ScatterDataPoint
{
    public ThreeTuple<float> coords { get; }
    public float value { get; }
    public ScatterDataPoint(ThreeTuple<float> coords, float value)
    {
        this.coords = coords;
        this.value = value;
    }
}

I also have this function that is supposed to find the maximum value of an array of data points

    {
        // Finds the maximum value of an BarData array
        float maxValue = data[0].value;
        foreach (BarDataPoint dataPoint in data)
        {
            maxValue = (maxValue < dataPoint.value) ? dataPoint.value : maxValue;
        }
        return maxValue;
    }

I would like to generalize this function, so that it can take both types (or any other type with a "value" field) and return its maximum value.

Is this possible? If yes, how? Or would you recommend a completely different design?

There are no problems having a struct implement an interface:

public interface IDataPoint
{
    float Value { get; }
}

public struct BarDataPoint : IDataPoint
public struct ScatterDataPoint : IDataPoint

Then you could do this:

{
    float maxValue = data[0].Value;
    foreach (IDataPoint dataPoint in data)
    {
        maxValue = (maxValue < dataPoint.Value) ? dataPoint.Value : maxValue;
    }
    return maxValue;
}

To avoid the performance hit caused by boxing in the above example, you could make the implementing method generic:

float GetMaxValue<TDataPoint>(TDataPoint[] data) where TDataPoint : IDataPoint
{
    float maxValue = data[0].Value;
    foreach (TDataPoint dataPoint in data)
    {
        maxValue = (maxValue < dataPoint.Value) ? dataPoint.Value : maxValue;
    }
    return maxValue;
}

Just be sure to always refer to data as TDataPoint within the generic method, as using IDataPoint will cause boxing (because interfaces are reference types).

The reason this works is because the generic method will be resolved to either float GetMaxValue(BarDataPoint[] data) or float GetMaxValue(ScatterDataPoint[] data) and not float GetMaxValue(IDataPoint[] data) .


As an aside, if you simply need to know the maximum value, Enumerable.Max should do exactly what you're after, without the need for the above approach:

BarDataPoint[] data = //...
float max = data.Max(x => x.Value);

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM