I made a dictionary-like container that supports key-wise arithmetic operations. I want it to "act" like a value type in the sense that it can be added, subtracted, and multiplied by other instances of the same container.
I'm making a set of stats containers for a game. The aforementioned arithmetic dictionary is to be the base class for all of the different stats containers (i.e. stats, stat multipliers, equipment stat multipliers, level up bonuses, etc.) using a common enum for their keys and a variety of data types for their values (i.e. integers, doubles, and number-like custom classes).
public class ArithmeticDictionary<TKey,TValue> :
IEnumerable<KeyValuePair<TKey,TValue>>,
System.Numerics.IAdditionOperators<
ArithmeticDictionary<TKey,TValue>,
ArithmeticDictionary<TKey,TValue>,
ArithmeticDictionary<TKey,TValue>>,
System.Numerics.ISubtractionOperators<
ArithmeticDictionary<TKey,TValue>,
ArithmeticDictionary<TKey,TValue>,
ArithmeticDictionary<TKey,TValue>>,
System.Numerics.IMultiplyOperators<
ArithmeticDictionary<TKey,TValue>,
ArithmeticDictionary<TKey,TValue>,
ArithmeticDictionary<TKey,TValue>>,
System.Numerics.IComparisonOperators<
ArithmeticDictionary<TKey,TValue>,
ArithmeticDictionary<TKey,TValue>,
bool>,
System.Numerics.IMinMaxValue<
ArithmeticDictionary<TKey,TValue>>,
System.Numerics.IAdditiveIdentity<
ArithmeticDictionary<TKey,TValue>,
ArithmeticDictionary<TKey,TValue>>
where TKey : notnull
where TValue :
System.Numerics.IAdditionOperators<TValue,TValue,TValue>,
System.Numerics.ISubtractionOperators<TValue,TValue,TValue>,
System.Numerics.IMultiplyOperators<TValue,TValue,TValue>,
System.Numerics.IComparisonOperators<TValue,TValue,bool>,
System.Numerics.IMinMaxValue<TValue>,
System.Numerics.IAdditiveIdentity<TValue,TValue>
{}
The functionality is all there, but every time I subclass the generic base class, I get a whole bunch of the same warning.
Here, Stat
is an enum.
public class Stats :
ArithmeticDictionary<Stat, uint>,
IEnumerable<KeyValuePair<Stat,uint>>,
System.Numerics.IAdditionOperators<Stats,Stats,Stats>,
System.Numerics.ISubtractionOperators<Stats,Stats,Stats>,
System.Numerics.IMultiplyOperators<Stats,Stats,Stats>,
System.Numerics.IComparisonOperators<Stats,Stats,bool>,
System.Numerics.IMinMaxValue<Stats>,
System.Numerics.IAdditiveIdentity<Stats,Stats>
{}
warning CA2260: The 'ArithmeticDictionary<TKey, TValue>' requires the 'TKey' type parameter to be filled with the derived type 'Stats'
From the warning, it seems to be due to ArithmeticDictionary
implementing a number of interfaces that have a TSelf
type parameter, but child classes are no longer of the same type.
My code still works, but 5 subclasses with 6 warnings each is a bit much.
Add a TSelf type parameter to IArithmeticDictionary. Inline with the answer to this question. Adding operator support to interfaces (Preview Feature in .NET 6)
I put some example code below that compiles, but ommits simmilar cases for brevity.
public interface IArithmeticDictionary<TSelf, TKey, TValue> :
IEnumerable<KeyValuePair<TKey, TValue>>,
System.Numerics.IAdditionOperators<TSelf,
TSelf,
TSelf>
where TSelf : IArithmeticDictionary<TSelf, TKey, TValue>
where TKey : notnull
where TValue :
System.Numerics.IAdditionOperators<TValue, TValue, TValue>
{
// Optional
public static TSelf operator +(IArithmeticDictionary<TSelf, TKey, TValue> left, TSelf right)
{
throw new NotImplementedException();
}
// Optional
static TSelf operator checked +(IArithmeticDictionary<TSelf, TKey, TValue> left, TSelf right)
{
throw new NotImplementedException();
}
}
public class Stats :
IArithmeticDictionary<Stats, Stat, uint>
{
public IEnumerator<KeyValuePair<Stat, uint>> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
public static Stats operator +(Stats left, Stats right)
{
throw new NotImplementedException();
}
}
public enum Stat
{
A,
B
}