2012-03-11 210 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