Home > Mobile >  There is no implicit conversion from CustomObject to System.IConvertible
There is no implicit conversion from CustomObject to System.IConvertible

Time:12-06

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];
}
  •  Tags:  
  • c#
  • Related