Search code examples
c#fizzbuzz

How can I return a new instance of a class as a string and use it as a parameter of a generic method?


I have this generic method to solve the fizzbuzz quiz but when I use the class instance as a parameter to the method. I get an empty output. Can anyone help out with this.

if input is divisible by 3 output Fizz
divisible by 5 output = Buzz
3 & 5 = FizzBuz<

    private static string FizzBuzz<T>(T item)
    {
        int itemLength = item.ToString().Length;
        string output = "";

        if (itemLength % 3 == 0)
        {
            output += "Fizz";
        }
        if (itemLength % 5 == 0)
        {
            output += "Buzz";
        }

        return output;
    }

here is a class

public class UserModel
{
    public string FirstName { get; set; }
    public string  LastName { get; set; }
}

//in the main method class

static void Main(string[] args)
{
    string result = (FizzBuzz("tests"));
    Console.WriteLine($"Tests: {result}");

    result = FizzBuzz(223);
    Console.WriteLine($"223:{result}");

    result = FizzBuzz ( new UserModel { FirstName = "Vic", LastName = "Okpas"});
    Console.WriteLine($" user model: {result}");
}

output:

Tests: Buzz
223: Fizz
user model:

the user model is supposed to output Fizz because the first name has 3 letters. Can anyone help me figure out what i am doing wrong.


Solution

  • The key is ToString() in int itemLength = item.ToString().Length;

    Let's restructure your program a little bit to see what's happening.

    static string FizzBuzz<T>(T item)
    {
        int itemLength = item.ToString().Length;
        string output = "";
    
        if (itemLength % 3 == 0)
        {
            output += "Fizz";
        }
        if (itemLength % 5 == 0)
        {
            output += "Buzz";
        }
        Console.WriteLine($"'{item.ToString()}' -> {itemLength} -> '{output}'");
        return output;
    }
    

    Now the following code

    FizzBuzz("tests");
    FizzBuzz(223);
    FizzBuzz(new UserModel
    {
        FirstName = "Vic",
        LastName = "Okpas"
    });
    

    prints

    'tests' -> 5 -> 'Buzz'
    '223' -> 3 -> 'Fizz'
    'UserModel' -> 9 -> 'Fizz'
    

    The issue is that ToString() for a class gives its name.

    With this knowledge, if you insist that your FizzBuzz should use ToString().Length as the number all we need to do teach the ItemModel class how to return FirstName from ToString():

    public class UserModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public override string ToString()
        {
            return FirstName;
        }
    }
    

    Now the output for

    FizzBuzz(new UserModel
    {
        FirstName = "Vic",
        LastName = "Okpas"
    });
    

    is

    'Vic' => 3 -> 'Fizz'
    

    Some notes

    A generic FizzBuzz?

    FizzBuzz methods cannot really be made generic because their input really is a number and nothing else. What this number is for a given type is something that cannot be decided inside the method.

    This is more sensible in my opinion:

    static string FizzBuzz(int x)
    {
        string output = "";
        if (x% 3 == 0)
        ...
    }
    
    // and then
    
    var userModel = new UserModel
    {
        FirstName = "Vic",
        LastName = "Okpas"
    }
    
    FizzBuzz(userModel.FirstName.Length);
    

    Interfaces

    If you really wish to make you FizzBuzz more generic you could make it accept and interface.

    static string FizzBuzz(IForFizzBuzz item)
    {
        int x = item.NumberForFizzBuzz;
        string output = "";
    
        if (x % 3 == 0)
        {
            output += "Fizz";
        }
        if (x % 5 == 0)
        {
            output += "Buzz";
        }
        Console.WriteLine($"'{x} -> '{output}'");
        return output;
    }
    
    public class UserModel: IForFizzBuzz
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public int NumberForFizzBuzz => FirstName.Length;
    }
    
    public interface IForFizzBuzz { 
        public int NumberForFizzBuzz {get; }
    
    }
    

    and then you can call it with your model

    FizzBuzz(new UserModel
    {
        FirstName = "Vic",
        LastName = "Okpas"
    });
    
    

    Generic vs object

    Since all types in C# provide ToString() your version of the method doesn't benefit from being generic and could just accept an object

    static string FizzBuzz(object item)
    {
        int itemLength = item.ToString().Length;
        string output = "";
    ...