2012-03-11 174 views
0

我在奇怪的情况下玩弄泛型,我遇到了一个奇怪的情况,其“解决方案”,我不希望工作。这里是有问题的代码...C#铸造奇怪

static TournamentGame<T, Y> make16Game<T, Y>(int gameId, int seed1, int seed2, List<Y> teams) 
     where T : TournamentTeam<Y> 
     where Y : Team 
    { 
     /* 
     * bunch of code removed for clarity 
     */ 

     // return that bad boy 
     return new TournamentGame<T, Y>(gameId, 
             (T)(new TournamentTeam<Y>(seed1, teams[seed1 - 1])), 
             (T)(new TournamentTeam<Y>(seed2, teams[seed2 - 1]))); 
    } 

看着这个,我看不到编译器如何允许这样做。我的直觉是,如果我曾经用T以外的TournamentTeam来调用它,我会得到一个运行时错误。如果我没有放入演员阵容,我会收到一个编译错误。我的直觉是否正确?我想要做的是强制约束,T必须有一个构造函数,需要StringY参数,但这是另一个问题。我想我也可以使用反射来获得T的构造函数,但其​​中的乐趣在哪里?

无论如何,想法?

编辑 的TournamentGame如下所示:

public class TournamentGame<T, Y> : Game<T> 
    where T : TournamentTeam<Y> 
    where Y : Team 
{ 
    public TournamentGame(int id, T t1, T t2, Region<T, Y> region = null) 
     : base(id, t1, t2) 
    { 
     // do your thang 
    } 
} 

public class Game<T> 
    where T : Team 
{ 
    private T mTeam1 = null; 

    private Game(int id) 
    { 
     // do your thang 
    } 

    public Game(int id, T t1, T t2) 
     : this(id) 
    { 
     // do your thang 
    } 

    public T Team1 
    { 
     get 
     { 
      // do your thang 
     } 
    } 
} 

对不起,离开了这一点。

+0

也许我错了,可是我什么也看不到一般在这种方法中,只是一个非常使用常规类型的尴尬的方式。\ – 2012-03-11 05:06:05

+0

好吧,我的使用泛型的很多原因在此代码示例中是隐藏的,因为泛型将用于正在使用的对象类型中,而不是在此特定代码中。该函数是另一个需要泛型的静态函数的辅助函数。但是,我更多地在回归声明中询问演员,如果这是一个好的或不好的主意。 – aaronburro 2012-03-11 05:36:02

+0

尽管如此,你是对的。这个问题与泛型没有任何关系,我意识到在我点击提交按钮之前,实际上改变了标题,但忘了删除泛型标记。现在删除该标签。 – aaronburro 2012-03-11 05:40:00

回答

1

我开始用你的代码(或多或少)和ReSharper的马上告诉我,投至T是不必要的:

public class Test 
{ 
    static TournamentGame<T, Y> make16Game<T, Y>(int gameId, int seed1, int seed2, List<Y> teams) 
     where T : TournamentTeam<Y> 
     where Y : Team 
    { 
     return new TournamentGame<T, Y>(gameId, 
             new TournamentTeam<Y>(seed1, teams[seed1 - 1]), 
             new TournamentTeam<Y>(seed2, teams[seed2 - 1])); 
    } 
} 

internal class Team { } 

internal class TournamentTeam<T> { 
    public TournamentTeam(int seed1, Team team) { 
     throw new NotImplementedException(); 
    } 
} 

internal class TournamentGame<T, Y> { 
    public TournamentGame(int gameId, TournamentTeam<Y> tournamentTeam, TournamentTeam<Y> tournamentTeam1) { 
     throw new NotImplementedException(); 
    } 
} 

所以需要对投至T是从别的地方来了。

static TournamentGame<T, Y> make16Game<T, Y>(int gameId, int seed1, int seed2, Func<int, Y, T> tournamentTeamFactory, List<Y> teams) 
     where T : TournamentTeam<Y> 
     where Y : Team 
    { 
     return new TournamentGame<T, Y>(gameId, 
      tournamentTeamFactory(seed1, teams[seed1 - 1]), 
      tournamentTeamFactory(seed2, teams[seed2 - 1])); 
    } 

编辑:如果你想要一个特定类型的“构造”对于T的,你总是可以沿着工厂方法传递既然你正在使用的构造函数代码,它是很清楚,为什么你需要一个投至T (以及为什么传递工厂方法,正如我上面所建议的,这是一个好主意)。如果你想限制TournamentGame只参加锦标赛球队(你的代码是),那么请提供一个直接参加锦标赛团队的构造函数。如果没有,那么你不应该在make16Game函数中创建TournamentTeams。想象一下以下内容:

public class AllStarTeam<T> : TournamentTeam<T> where T : Team 
{ 
    public AllStarTeam(int seed1, Team team) : base(seed1, team) 
    { 
     throw new NotImplementedException(); 
    } 
} 

那么这个编译,但引发运行时异常(坏事):

Test.make16Game<AllStarTeam<T>, T>(5, 5, 5, new List<T>()); 
+0

奇怪的是,它会说演员是没有必要的。 4.0上的VS2010给出了“无法从TournamentTeam 转换为T”的错误,这是有道理的。如果我在比赛队伍延续的方法中通过了“B”类型的话?当我试图将一个TournamentTeam 对象投入到B中时,我应该得到一个InvalidCastException,或者我期望的。 – aaronburro 2012-03-11 06:07:23

+1

我发布的第一个代码示例使用VS2010在4.0上进行编译。也许你的'TournamentGame'类的构造函数是不同的?您没有发布该部分。 – 2012-03-11 06:19:53

+0

你是对的,让我给构造函数。在问题中...... – aaronburro 2012-03-11 06:22:24

1

如果我理解你是正确的,你不能在泛型的构造函数中指定这样的约束。 Here is some thoughts与您的问题相关。

+0

有趣的阅读。他似乎在研究我一直在处理的相同问题。 – aaronburro 2012-03-11 05:36:36