我知道C#中没有模板专业化,但这有效(至少在编译时):
public T test0<T>()
{
return default(T);
}
// handling T=float case
public float test0()
{
return 0;
}
这甚至没有编译:
public T this[int i]
{
get { return default(T); }
set { }
}
public float this[int i]
{
get { return 0; }
set { }
}
也不是这个
public float this<float>[int i]
{
get { return 0; }
set { }
}
它说&#34; ..已经定义了一个名为&#39; this&#39;使用相同的参数类型&#34;在浮动版本上。我可以检查通用[]
访问器中的所有类型,但是太多if-elseif
和typeof()
会降低性能(我将把它用作非托管数组而不是托管数组)和dynamic
不是一个选项,因为我主要使用.Net 3.5。在另一个问题中,我已经知道我无法获得泛型类型的指针,因此我决定每个float,double,int和byte类型使用多个重载,并在此数组访问重载中使用这些重载(但是不是同一种方法,而是不同的方法,不会失去性能。)
某些基本类型(如[]
)是否可以重载通用float
?更具体地说,一个类本身可以像以下一样使用吗?
MyArr<float> arr = new MyArr<float>();
// specifically rounds to nearest for floats
arr[100]+=500f;
MyArr<int> arr = new MyArr<int>();
// specifically adds 1 to some performance counter variable
arr[100]+=500;
MyArr<byte> arr = new MyArr<byte>();
// does nothing special
arr[100]+=50;
如果答案为否,那么我将使用额外的Interface
来实现此功能,但我不确定是否可以将另一个界面添加到项目中单个功能。 (我应该问&#34;是否只为一种方法添加另一个界面好吗?&#34;在另一个问题中?)
答案 0 :(得分:1)
我认为以下内容可能会有所帮助:
main()
您可以拥有任意数量的优化类型,并在基类中保留一些常用逻辑。
您还可以考虑将基类定义为抽象,并确保始终使用优化版本。
答案 1 :(得分:1)
您可以使用包含helper class
和nested generic class
委托的Func/Action
来实现Indexer / Property / Method的专业化。
internal static class IndexerImpl
{
private static T IndexerDefaultImpl<T>(int i) => default(T); //default implementation
private static T IndexerImpl2<T>(int i) => default(T); //another implementation for short/int/long
private static string IndexerForString(int i) => (i * i).ToString(); //specialization for T=string
private static DateTime IndexerForDateTime(int i) => new DateTime(i * i * i); //specialization for T=DateTime
static IndexerImpl() //install the specializations
{
Specializer<string>.Fun = IndexerForString;
Specializer<DateTime>.Fun = IndexerForDateTime;
Specializer<short>.Fun = IndexerImpl2<short>;
Specializer<int>.Fun = IndexerImpl2<int>;
Specializer<long>.Fun = IndexerImpl2<long>;
}
internal static class Specializer<T> //specialization dispatcher
{
internal static Func<int, T> Fun;
internal static T Call(int i)
=> null != Fun
? Fun(i)
: IndexerDefaultImpl<T>(i);
}
}
public class YourClass<T>
{
public T this[int i] => IndexerImpl.Specializer<T>.Call(i);
}
如果您需要YourClass
的实例来计算返回值,您可以添加一个参数来传递所需的信息:
internal static class IndexerImpl
{
private static T IndexerDefaultImpl<T>(int i, YourClass<T> yourClass) => default(T); //default implementation
private static T IndexerImpl2<T>(int i, YourClass<T> yourClass) => default(T); //another implementation for short/int/long
private static string IndexerForString<T>(int i, YourClass<T> yourClass) => (i * i).ToString(); //specialization for T=string
private static DateTime IndexerForDateTime<T>(int i, YourClass<T> yourClass) => new DateTime(i * i * i); //specialization for T=DateTime
static IndexerImpl() //install the specializations
{
Specializer<string>.Fun = IndexerForString;
Specializer<DateTime>.Fun = IndexerForDateTime;
Specializer<short>.Fun = IndexerImpl2;
Specializer<int>.Fun = IndexerImpl2;
Specializer<long>.Fun = IndexerImpl2;
}
internal static class Specializer<T> //specialization dispatcher
{
internal static Func<int, YourClass<T>, T> Fun;
internal static T Call(int i, YourClass<T> yourClass)
=> null != Fun
? Fun(i, yourClass)
: IndexerDefaultImpl(i, yourClass);
}
}
public class YourClass<T>
{
public T this[int i] => IndexerImpl.Specializer<T>.Call(i, this);
}
在专门设计通用索引器时,需要非泛型辅助类。
在专门化非泛型类的通用属性/方法时,default implementation
/ specializations
和nested specialization dispatcher class
可以直接放在您的班级中。
您需要注意的是,不要将专业化安装到泛型类的静态构造函数中。
此外,如果您需要部分特化,您可以使用通用辅助类,其参数化类型不需要专门化:
internal static class GetValueImpl<R, S>
{
private static T DefImpl<T>(R r, S s) => default(T);
private static int IntRet(R r, S s) => int.MaxValue;
internal static class Specializer<T>
{
internal static Func<R, S, T> Fun;
internal static T Call(R r, S s) => null != Fun ? Fun(r, s) : DefImpl<T>(r, s);
}
static GetValueImpl()
{
Specializer<int>.Fun = IntRet;
}
}
public class TestClass
{
//R and S are not specialized, we are specializing T
public T GetValue<R, S, T>(R r, S s) => GetValueImpl<R, S>.Specializer<T>.Call(r, s);
}
使用这种方式实现部分特化,你必须意识到,如果用不同的非专用类型多次调用嵌套的专业化类,辅助类的静态构造函数将运行多次:
public void Test()
{
var foo = new TestClass();
//GetValueImpl<long, long> will be created at runtime
var v1 = foo.GetValue<long, long, int>(1, 2); //GetValueImpl<long, long>.Specializer<int> will be called, specialized
var v2 = foo.GetValue<long, long, string>(1, 2); //GetValueImpl<long, long>.Specializer<string> will be called
var v3 = foo.GetValue<long, long, long>(1, 2); //GetValueImpl<long, long>.Specializer<long> will be called
//GetValueImpl<long, int> will be created at runtime
var v4 = foo.GetValue<long, int, int>(1, 2); //GetValueImpl<long, int>.Specializer<int> will be called, specialized
var v5 = foo.GetValue<long, int, double>(1, 2); //GetValueImpl<long, int>.Specializer<double> will be called
}
请注意,静态构造函数将为GetValueImpl<long, long>
和GetValueImpl<long, int>
运行2次,因此不要在辅助类的静态构造函数中添加额外的代码。