泛型如何处理构造函数
How do Generics handle constructors
我有一个泛型 class,它具有以下构造函数 1. Map(int resolution)
、2. Map(int resolution, T defaultValue)
、3. Map(int width, int height)
和 4. Map(int width, int height, T defaultValue)
,如果其中一个继承 classes 需要 map,构造函数 2 和 3 各有 2 个参数,在 map 的情况下它们都是整数。
public abstract class Map<T> {
private T[,] m_Map;
private T m_DefaultValue;
public T this[int x, int y] {
get {
return InRange(x,y)?m_Map[x,y]:DefaultValue;
}
set {
if(InRange(x,y)) { // Included to handle confusion between retrieving a non-existent position, and setting one.
m_Map[x,y] value;
}
}
}
public int Width{get { return m_Map.GetLength(0); } }
public int Height{get { return m_Map.GetLength(1); } }
public virtual T DefaultValue { get { return m_DefaultValue; } set{ m_DefaultValue = value; } }
public Map(int resolution) : this(resolution, resolution, default) {}
public Map(int resolution, T defaultValue) : this(resolution, resolution, defaultValue) {}
public Map(int width, int height) : this(width, height, default) {}
public Map(int width, int height, T defaultValue) {
m_Map = new T[width, height];
m_DefaultValue = defaultValue;
}
public bool InRange(int x, int y) {
return x>=0&&x<m_Map.GetLength(0)&&y>=0&&y<m_Map.GetLength(1);
}
}
您可以使用 named arguments 来消除方法的歧义。
//Call Map(int,int)
var x = new Map<int>(width: 1, height: 2);
//Call Map(int, T)
var x = new Map<int>(width: 1, defaultValue: 3);
同样适用于 base
关键字。
class MyClass : Map<int>
{
public MyClass(int width, int defaultValue) : base( width: width, defaultValue: defaultValue)
{
}
}
这在 CLI 中在技术上是可行的。 ECMA-335 specification 特别指出:
II.9.8 Signatures and binding
It is possible for distinct members to have identical types when instantiated, but which can be distinguished by MemberRef.
[Example:
.class public C`2<S,T> {
.field string f
.field !0 f
.method instance void m(!0 x) {...}
.method instance void m(!1 x) {...}
.method instance void m(string x) {...}
}
The closed type C``2<string,string>
is valid: it has three methods called m
, all with the same parameter type; and two fields called f
with the same type. They are all distinguished through the MemberRef
encoding described above:
string C`2<string, string>::f
!0 C<string, string>::f
void C`2<string, string>::m(!0)
void C`2<string, string>::m(!1)
void C`2<string, string>::m(string)
The way in which a source language might resolve this kind of overloading is left to each individual language. For example, many might disallow such overloads.
end example]
在 C# 的情况下,这不被认为是非法的,将使用 standard method overload resolution:
- Otherwise, given any two members of the set,
M
and N
, apply the following tie-breaking rules, in order:
..snip..
bv. Before type arguments have been substituted, if M
is less generic (Section Genericity) than N
, eliminate N
from the set.
所以非通用的优先于通用的。
请注意,重载决策仅考虑编译时可用的信息(dynamic
除外)。所以构造函数
public Map(int resolution, T defaultValue) : this(resolution, resolution, defaultValue) {}
会一直打电话
public Map(int width, int height, T defaultValue) {
即使 Map<int>
也永远不要调用这个
public Map(int width, int height, int defaultValue) {
我有一个泛型 class,它具有以下构造函数 1. Map(int resolution)
、2. Map(int resolution, T defaultValue)
、3. Map(int width, int height)
和 4. Map(int width, int height, T defaultValue)
,如果其中一个继承 classes 需要 map
public abstract class Map<T> {
private T[,] m_Map;
private T m_DefaultValue;
public T this[int x, int y] {
get {
return InRange(x,y)?m_Map[x,y]:DefaultValue;
}
set {
if(InRange(x,y)) { // Included to handle confusion between retrieving a non-existent position, and setting one.
m_Map[x,y] value;
}
}
}
public int Width{get { return m_Map.GetLength(0); } }
public int Height{get { return m_Map.GetLength(1); } }
public virtual T DefaultValue { get { return m_DefaultValue; } set{ m_DefaultValue = value; } }
public Map(int resolution) : this(resolution, resolution, default) {}
public Map(int resolution, T defaultValue) : this(resolution, resolution, defaultValue) {}
public Map(int width, int height) : this(width, height, default) {}
public Map(int width, int height, T defaultValue) {
m_Map = new T[width, height];
m_DefaultValue = defaultValue;
}
public bool InRange(int x, int y) {
return x>=0&&x<m_Map.GetLength(0)&&y>=0&&y<m_Map.GetLength(1);
}
}
您可以使用 named arguments 来消除方法的歧义。
//Call Map(int,int)
var x = new Map<int>(width: 1, height: 2);
//Call Map(int, T)
var x = new Map<int>(width: 1, defaultValue: 3);
同样适用于 base
关键字。
class MyClass : Map<int>
{
public MyClass(int width, int defaultValue) : base( width: width, defaultValue: defaultValue)
{
}
}
这在 CLI 中在技术上是可行的。 ECMA-335 specification 特别指出:
II.9.8 Signatures and binding
It is possible for distinct members to have identical types when instantiated, but which can be distinguished by MemberRef.
[Example:.class public C`2<S,T> { .field string f .field !0 f .method instance void m(!0 x) {...} .method instance void m(!1 x) {...} .method instance void m(string x) {...} }
The closed type
C``2<string,string>
is valid: it has three methods calledm
, all with the same parameter type; and two fields calledf
with the same type. They are all distinguished through theMemberRef
encoding described above:string C`2<string, string>::f !0 C<string, string>::f void C`2<string, string>::m(!0) void C`2<string, string>::m(!1) void C`2<string, string>::m(string)
The way in which a source language might resolve this kind of overloading is left to each individual language. For example, many might disallow such overloads. end example]
在 C# 的情况下,这不被认为是非法的,将使用 standard method overload resolution:
- Otherwise, given any two members of the set,
M
andN
, apply the following tie-breaking rules, in order:
..snip..
bv. Before type arguments have been substituted, ifM
is less generic (Section Genericity) thanN
, eliminateN
from the set.
所以非通用的优先于通用的。
请注意,重载决策仅考虑编译时可用的信息(dynamic
除外)。所以构造函数
public Map(int resolution, T defaultValue) : this(resolution, resolution, defaultValue) {}
会一直打电话
public Map(int width, int height, T defaultValue) {
即使 Map<int>
public Map(int width, int height, int defaultValue) {