Home > Blockchain >  Why is a default interface method used instead of a class field?
Why is a default interface method used instead of a class field?

Time:05-17

I have code like below. Interface with default implementation. And the user who uses this interface. But for some reason in the switch case my code uses the default implementation of the interface for the "Name' instead of the class implementation. What should i change to see "Ben" in console?

namespace ConsoleApp1
{
    public interface IUser
    {
        // Interface with default implementation
        public string Name { get => "Tom"; }
    }

    // User using this interface
    public class BenUser : IUser
    {
        public string Name = "Ben";
    }

    public static class MainClass
    {
        public static void ShowName(IUser user)
        {
            switch (user.Name)
            {
                case "Ben": // I expected the code to run here
                    Console.WriteLine("Ben");
                    break;

                case "Tom": // But the code goes here
                    Console.WriteLine("Tom");
                    break;
            }
        }

        static void Main()
        {
            // Create a user with Name "Ben"
            var ben = new BenUser();
            ShowName(ben);  // In console i see "Tom" for some reason
        }
    }
}

I can't figure out why the code is behaving like this.

CodePudding user response:

As mentioned in comments, you need to implement the interface using the same shape in your class - as a property with a get.

public interface IUser
{
    // Interface with default implementation
    public string Name { get => "Tom"; }
}

// User using this interface
public class BenUser : IUser
{
    public string Name { get => "Ben"; }
}

public static class MainClass
{
    public static void ShowName(IUser user)
    {
        switch (user.Name)
        {
            case "Ben": // I expected the code to run here
                System.Console.WriteLine("Ben");
                break;

            case "Tom": // But the code goes here
                System.Console.WriteLine("Tom");
                break;
        }
    }

    static void Main()
    {
        // Create a user with Name "Ben"
        var ben = new BenUser();
        ShowName(ben);  // In console i see "Tom" for some reason
    }
}

CodePudding user response:

This is my edit to show some more standard practices, please read through the comments and see if it makes anything more clear. The standard practice for creating members is to use accesslevel Type VariableName { get; set; }

namespace ConsoleApp1
{
    public interface IUser
    {
        //denotes that this is set by construction, cannot be set afterwards 
        public string Name { get; }
    }

    // User using this interface
    public class BenUser : IUser
    {
        // Standard 'getter' only member with a compiled return value
        public string Name
        {
            get
            {
                return "Ben";
            }
        }
    }

    public class User : IUser
    {
        // private settable string to use with construction
        private string _name;

        // constructor
        public User(string userName)
        {
           // sets the private variable to desired value
            _name = userName;
        }

        // public 'getter' that returns the set value
        public string Name
        {
            get
            {
                return _name;
            }
        }
    }

    public static class MainClass
    {
        public static void ShowName(IUser user)
        {
            Console.WriteLine(user.Name);
        }

        static void Main()
        {
            // Create a user with static Name "Ben"
            var ben = new BenUser();
            ShowName(ben);

            // Create a user with variable Name set as "Carl"
            var carl = new User("Carl");
            ShowName(carl);
        }
    }
}

CodePudding user response:

The Name in IUser is a property while Name in BenUser is a field. With your code when we do user.Name it calls the get method defined in IUser instead of getting value of Name field from BenUser. Here is a sample implementation for fixing your bug.

public class BenUser : IUser
{
    public string Name { get => "Ben"; }
}

I would recommend to not do it the way you are doing because Name identifier has become embiguos

  • Related