Stuck on this for a while now and I dont understand what is going on. I have an Object of Level which populates on App start. Object has 3 classes. I need to return different Object depending on type T
on my method but I keep getting this error. This is my first time having to deal with conversions of types on the same method.
There is no implicit conversion from uCue_Silver.Models.Game to System.IConvertible
Many Thanks in Advance.
Level Single File Object
public class Level
{
public List<Game> Games { get; set; }
}
public class Game
{
public string game { get; set; }
public List<Word> words { get; set; }
}
public class Word
{
public string word { get; set; }
public string ipa { get; set; }
public string image { get; set; }
public string sound { get; set; }
public string video { get; set; }
}
Method
public T GetResources<T>(int level = 1, int word = 1, string gameVersion = "bronze", bool shouldReturnGamesOnly = false) where T : IConvertible
{
if (versions.Contains(gameVersion))
{
if (!shouldReturnGamesOnly)
{
if (gameVersion.ToLower() == "bronze")
{
if (BronzeGameLevels == null)
throw new NullReferenceException("Bronze Game Levels are Null. Potential missing data in BronzeLevels.json file.");
return (T)Convert.ChangeType(BronzeGameLevels.Games[level - 1].words[word - 1], typeof(T));
}
else if (gameVersion.ToLower() == "silver")
{
}
}else if (shouldReturnGamesOnly)
{
if (gameVersion.ToLower() == "bronze")
{
if (BronzeGameLevels == null)
throw new NullReferenceException("Bronze Game Levels are Null. Potential missing data in BronzeLevels.json file.");
return (T)Convert.ChangeType(BronzeGameLevels.Games[level - 1], typeof(T));
}
else if (gameVersion.ToLower() == "silver")
{
}
}
}
else throw new GameVersionOutOfRangeException();
throw new UnreachableCodeException();
}
Method 1 Using Above Method
public string GetWord(int level, int word, string gameVersion = "bronze")
{
var res = GetResources<Word>(level, word, gameVersion); //Error
return res.word;
}
Method 2 Using the same method different type
public int GetTotalWordsInCurrentGame(int level, string gameVersion = "bronze")
{
var res = GetResources<Game>(level, gameVersion: gameVersion); //Error
return res.words.Count;
}
Update
BronzeGameLevels Declaration
async void LoadLevelsAsync()
{
IJsonReader reader = DependencyService.Get<IJsonReader>();
var bronzeLevels = await reader.ReadJsonFile("BronzeLevels.json");
BronzeGameLevels = JsonConvert.DeserializeObject<Level>(bronzeLevels);
}
CodePudding user response:
You are misusing what generics are meant for in C#. Your method is meant to return different types based on the value of the shouldReturnGamesOnly
parameter.
This is not good design. Don't do this.
Instead, write two different methods, one that returns a Game
, and one that returns a Word
.The one that returns a Word
can internally call the one that returns a Game
so that you don't have duplicate code.
CodePudding user response:
The generic method GetResources
has thet generic parameter T
where the constraint is T
implement IConvertible
:
public T GetResources<T>(...) where T : IConvertible
To sumary, it's only possible to call this method specifying a type that implement IConvertible
.
In you case, you call this method with the types Game
and Word
... that don't implement IConvertible
, then you get this error.
The naive solution is to implement IConvertible
in the types Game
and Word
, but ...
See this minimalist version :
public T GetResources<T>(int level, int word, bool shouldReturnGamesOnly)
{
if (shouldReturnGamesOnly)
return (T)BronzeGameLevels.Games[level - 1]
else
return (T)BronzeGameLevels.Games[level - 1].words[word - 1];
}
When shouldReturnGamesOnly
is true, then the methode return a Game
, else it return a Word
. But it's possible to call the method with shouldReturnGamesOnly at true and expected a Word
:
GetResources<Word>(level, word, shouldReturnGamesOnly: true); // shouldReturnGamesOnly but ask a Word ressource
It's just a edge case than you can ignore... but if you want improve the resilience of your code, I suggest you cut GetResources
in two distinct methods like:
public Word GetWord(int level, int word)
{
return BronzeGameLevels.Games[level - 1].words[word - 1];
}
public Word GetGame(int level)
{
return BronzeGameLevels.Games[level - 1];
}