Conditional generic type constructor in C#?
c#, constructor, generics, wildcard
Solution
There's a trick that you could apply here. It's fexible for many scenarios.
internal static class FooHelper
{
private static class DefaultData<T>
{
public static T Value = default(T);
}
static FooHelper()
{
DefaultData<int>.Value = 42;
DefaultData<string>.Value = "Hello World";
}
// From @JeffreyZhao:
//
// Use a static method to trigger the static constructor automatically,
// or we need to use RuntimeHelpers.RunClassConstructor to make sure
// DefaultData is corrected initialized.
//
// The usage of RuntimeHelpers.RunClassConstructor is kept but commented.
// Using GetDefault<T>() is a better approach since static Foo() would be
// called multiple times for different generic arguments (although there's
// no side affect in this case).
//
// Thanks to @mikez for the suggestion.
public static T GetDefault<T>()
{
return DefaultData<T>.Value;
}
}
public class Foo<T>
{
/* See the comments above.
static Foo()
{
RuntimeHelpers.RunClassConstructor(typeof(FooHelper).TypeHandle);
}
*/
public T Data { get; protected set }
public Foo()
{
Data = FooHelper.GetDefault<T>();
}
}
You could specify the default values for limited types, and the result of them would be kept to default values.
This trick has several variations in practice. In my project, we use a generic `ITypeConverter<T>` instead of the build in `TypeConverter` to avoid unnecessary boxing:
public interface ITypeConverter<T>
{
bool CanConvertTo<TTarget>();
TTarget ConvertTo(T value);
}
The same trick could be applied as:
public class LongConverter : ITypeConverter<long>
{
private static class Op<TTarget>
{
public static Func<long, TTarget> ConvertTo;
}
static LongConverter()
{
Op<string>.ConvertTo = v => v.ToString();
Op<DateTime>.ConvertTo = v => new DateTime(v);
Op<int>.ConvertTo = v => (int)v;
}
public TTarget ConvertTo<TTarget>(T value)
{
return Op<TTarget>.ConvertTo(value);
}
}
Elegant, fast and clean.
Problem
Say you have a generic class `Foo`: ``` public class Foo<T> { public T Data { get; protected set; } } ``` Is it possible to define a constructor that is only applicable if `T` inherits (or is) a specific type. For instance say `T` is an `int`: ``` public Foo () { this.Data = 42; } ``` The type constraint should be checked at compile-time. This might be useful for optimization. Say for instance you have an `IEnumerable<T>` and you wish to make a "cache" (since LINQ queries can be quite expensive). Now if the `IEnumerable<T>` is already an `IList<T>`, it is useful not to copy data. On the other hand if it is really a LINQ query, another constructor can store the data in an array. As a workaround, one can of course inherit `Foo` (e.g. `IntFoo`) and define a constructor there: ``` public class IntFoo : Foo<int> { public IntFoo () { this.Data = 42; } } ``` A problem with this approach is however that `private` data is not accessible (or one has to make it `protected`). Are there some other disadvantages, or does one is supposed to model type-specific constructors this way?