Is there something similar to this C++ template?
template
class B
{
int f()
{
return A;
}
}
I want to mak
The short answer is no.
It doesn't fit the way C# generics, as apposed to C++ templates, work.
The .net generics are not a language feature, they are a runtime feature. The runtime knows how to instantiate generics from special generic bytecode which is rather restricted compared to what C++ templates can describe.
Compare this with C++ templates, which basically instantiate the whole AST of the class using substituted types. It'd be possible to add AST based instantiation to the runtime, but it'd certainly be much more complex than the current generics.
Without features like value-type arrays (which only exist in unsafe code), recursive template instantiation or template specialization using such parameters wouldn't be very useful either.
C# does not support non-type generic parameters like C++ does.
C# generics are far simpler and less capable than C++ templates. MSDN has a succinct list of Differences Between C++ Templates and C# Generics.
C# generics are specialized at run-time, whereas C++ templates are processed at compile-time to make an entirely new type. Given this, the runtime simply doesn't have the features to process non-type parameters (it's not just a C# issue).
The following approach may be useful depending on what you're trying to accomplish. The size of the underlying collection is determined by an abstract property.
public abstract class TupleBase
{
protected abstract int NumElems { get; }
protected object[] values;
protected TupleBase(params object[] init)
{
if (init.Length != NumElems)
{
throw new ArgumentException($"Collection must contains {NumElems} elements", nameof(init));
}
values = new object[NumElems];
for (int i = 0; i < init.Length; i++)
{
values[i] = init[i];
}
}
protected object Get(int idx) => values[idx];
protected void Set(int idx, object value) => values[idx] = value;
}
public class Tuple1<T> : TupleBase {
protected override int NumElems => 1;
public Tuple1(T val0) : base(val0) { }
public T Get0() => (T)Get(0);
public void Set0(T value) => Set(0, value);
}
public class Tuple2<T, U> : TupleBase {
protected override int NumElems => 2;
public Tuple2(T val0, U val1) : base(val0, val1) { }
public T Get0() => (T)Get(0);
public U Get1() => (U)Get(1);
public void Set0(T value) => Set(0, value);
public void Set1(U value) => Set(1, value);
}
public class Tuple3<T, U, V> : TupleBase
{
protected override int NumElems => 3;
public Tuple3(T val0, U val1, V val2) : base(val0, val1, val2) { }
public T Get0() => (T)Get(0);
public U Get1() => (U)Get(1);
public V Get2() => (V)Get(2);
public void Set0(T value) => Set(0, value);
public void Set1(U value) => Set(1, value);
public void Set2(V value) => Set(2, value);
}
public class Tuple4<T, U, V, W> : TupleBase
{
protected override int NumElems => 4;
public Tuple4(T val0, U val1, V val2, W val3) : base(val0, val1, val2, val3) { }
public T Get0() => (T)Get(0);
public U Get1() => (U)Get(1);
public V Get2() => (V)Get(2);
public W Get3() => (W)Get(3);
public void Set0(T value) => Set(0, value);
public void Set1(U value) => Set(1, value);
public void Set2(V value) => Set(2, value);
public void Set3(W value) => Set(3, value);
}
public class Tuple5<T, U, V, W, X> : TupleBase
{
protected override int NumElems => 5;
public Tuple5(T val0, U val1, V val2, W val3, X val4) : base(val0, val1, val2, val3, val4) { }
public T Get0() => (T)Get(0);
public U Get1() => (U)Get(1);
public V Get2() => (V)Get(2);
public W Get3() => (W)Get(3);
public X Get4() => (X)Get(4);
public void Set0(T value) => Set(0, value);
public void Set1(U value) => Set(1, value);
public void Set2(V value) => Set(2, value);
public void Set3(W value) => Set(3, value);
public void Set4(X value) => Set(4, value);
}
A workaround to this limitation is to define a class which itself exposes the literal value you are interested in. For example:
public interface ILiteralInteger
{
int Literal { get; }
}
public class LiteralInt10 : ILiteralInteger
{
public int Literal { get { return 10; } }
}
public class MyTemplateClass< L > where L: ILiteralInteger, new( )
{
private static ILiteralInteger MaxRows = new L( );
public void SomeFunc( )
{
// use the literal value as required
if( MaxRows.Literal ) ...
}
}
Usage:
var myObject = new MyTemplateClass< LiteralInt10 >( );