Allow generics on indexer #2054
Replies: 10 comments 1 reply
-
Why not just make the class generic? |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt Presumably Loki wants to use a different |
Beta Was this translation helpful? Give feedback.
-
@jnm2 |
Beta Was this translation helpful? Give feedback.
-
My current use case is that I have a table that contains different Types in different Columns.
So the most natural way to describe this with classes would be a class public abstract class Table {
public abstract T this<T>[P<T> key, int inedx] { get; }
public abstract int Count { get; }
} Currently I'm using a method instead of an indexer. Of course that works, but (in my opinion) from an API design perspective the indexer would be the desired approach. |
Beta Was this translation helpful? Give feedback.
-
Hmm. |
Beta Was this translation helpful? Give feedback.
-
IMO, this should be extended to generic properties, allowing: class SomeClass
{
public T SomeProp<T> { get => ...; set => ...; }
}
SomeClass obj = new SomeClass(...);
obj.SomeProp<int> = 42;
I actually needed this a couple of times in my projects (I solved it using some Indexer wrapper classes). |
Beta Was this translation helpful? Give feedback.
-
@Unknown6656 |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt public struct P<T> : IEquatable<P<T>>
{
internal readonly Guid Id;
internal static P<T> Empty => default;
public P(Guid id)
{
this.Id = id;
}
internal static P<T> Create() => new P<T>(Guid.NewGuid());
public override bool Equals(object obj)
{
return obj is P<T> && this.Equals((P<T>)obj);
}
public bool Equals(P<T> other)
{
return this.Id == other.Id;
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
public static bool operator ==(P<T> p1, P<T> p2)
{
return p1.Equals(p2);
}
public static bool operator !=(P<T> p1, P<T> p2)
{
return !(p1 == p2);
}
}
internal abstract class Table
{
public static readonly P<double> PropabilityKey = P<double>.Empty;
public abstract int Count { get; }
protected abstract bool InternalContains<T>(P<T> key);
public bool Contains<T>(P<T> key) => PropabilityKey.Id == key.Id || this.InternalContains(key);
public abstract T GetValue<T>(P<T> p, int index);
}
internal class SingelVariableTable<T> : Table
{
private readonly P<T> variable;
private readonly (T value, double propability)[] distribution;
public SingelVariableTable(P<T> variable, params (T value, double propability)[] distribution)
{
this.variable = variable;
this.distribution = distribution;
}
public override int Count => this.distribution.Length;
protected override bool InternalContains<T>(P<T> key) => this.variable.Id == key.Id;
public override T1 GetValue<T1>(P<T1> p, int index)
{
switch (p)
{
case P<T> input when input.Id == this.variable.Id:
return (T1)(object)this.distribution[index].value;
case P<double> input when input.Id == PropabilityKey.Id:
return (T1)(object)this.distribution[index].propability;
default:
throw new KeyNotFoundException($"Key with id {p.Id}.");
}
}
}
internal class CombinationTable<TIn1, TIn2, TOut> : Table
{
private readonly Table First;
private readonly Table Seccond;
private readonly P<TOut> ownP;
private readonly Func<TIn1, TIn2, TOut> func;
public P<TIn1> FirstCalculationVariable { get; }
public P<TIn2> SeccondCalculationVariable { get; }
public CombinationTable(Table first, Table seccond, P<TOut> p, P<TIn1> firstCalculation, P<TIn2> seccondCalculation, Func<TIn1, TIn2, TOut> func)
{
this.First = first;
this.Seccond = seccond;
this.ownP = p;
this.FirstCalculationVariable = firstCalculation;
this.SeccondCalculationVariable = seccondCalculation;
this.func = func;
}
public override int Count
{
get
{
return this.ParentTablesAreSame
? this.First.Count
: this.First.Count * this.Seccond.Count;
}
}
private bool ParentTablesAreSame => this.First == this.Seccond;
public override T GetValue<T>(P<T> p, int index)
{
if (index >= this.Count)
throw new IndexOutOfRangeException($"The Index was out of Range index:{index} count:{this.Count}");
int firstIndex;
int secconedIndex;
if (this.ParentTablesAreSame)
{
firstIndex = index;
secconedIndex = index;
}
else
{
firstIndex = index % this.First.Count;
secconedIndex = index / this.First.Count;
}
if (p.Id == PropabilityKey.Id)
{
if (this.ParentTablesAreSame)
return this.First.GetValue(p, index);
return (T)(object)(this.First.GetValue(PropabilityKey, firstIndex) * this.Seccond.GetValue(PropabilityKey, secconedIndex));
}
if (p.Id == this.ownP.Id)
{
var firstValue = this.First.GetValue(this.FirstCalculationVariable, firstIndex);
var seccondValue = this.Seccond.GetValue(this.SeccondCalculationVariable, secconedIndex);
return (T)(object)this.func(firstValue, seccondValue);
}
if (this.First.Contains(p))
return this.First.GetValue(p, firstIndex);
if (this.Seccond.Contains(p))
return this.Seccond.GetValue(p, secconedIndex);
throw new KeyNotFoundException($"Key with id {p.Id} of type {typeof(TIn1)} not found.");
}
protected override bool InternalContains<T1>(P<T1> key) => key.Id == this.ownP.Id ? true : this.First.Contains(key) || this.Seccond.Contains(key);
}
} You can then use it as follows: var x = P<int>.Create();
var y = P<int>.Create();
var xTable = new SingelVariableTable<int>(x, (1, 1.0 / 6), (2, 1.0 / 6), (3, 1.0 / 6), (4, 1.0 / 6), (5, 1.0 / 6), (6, 1.0 / 6));
var yTable = new SingelVariableTable<int>(y, (1, 1.0 / 6), (2, 1.0 / 6), (3, 1.0 / 6), (4, 1.0 / 6), (5, 1.0 / 6), (6, 1.0 / 6));
var z = P<bool>.Create();
var table = new CombinationTable<int, int, bool>(xTable, yTable, z, x, y, (inx, iny) => inx < iny);
for (int i = 0; i < table.Count; ++i)
{
Console.WriteLine($"x:\t{table.GetValue(x, i)}\ty:\t{table.GetValue(y, i)}\tp:\t{table.GetValue(Table.PropabilityKey, i)}");
}
Console.ReadKey(true); |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt The typical uses I've seen for this are on command line argument collections where you want to pull out a bool or int or string given some name, or environment variable collections, or on settings or parameters read out of a file. Generic methods are good enough for these situations as far as I know, but the situations do exist. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Allow a generic type parameter on indexer definition.
This could allow strongly typed registry's.
Update A proposal in the Roslyn repository(#523) is far better written. Thanks @ufcpp
Beta Was this translation helpful? Give feedback.
All reactions