Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading two functions with object and list<object> parameter

Tags:

c#

Consider this code:

static void Main(string[] args)
    {
        Log("Test");//Call Log(object obj)
        Log(new List<string>{"Test","Test2"});;//Also Call Log(object obj)
    }

    public static void Log(object obj)
    {
        Console.WriteLine(obj);
    }

    public static void Log(List<object> objects)
    {
        foreach (var obj in objects)
        {
            Console.WriteLine(obj);
        }
    }  

In first line i call log with a string value and it invokes Log(object obj) but in the second line i call Log with list of string new List<string>{"Test","Test2"} but compiler invoke Log(object obj) instead of Log(List<object> objects).

Why compiler has this behavior?

How can i call the second log with list of string?

like image 426
Behrad Farsi Avatar asked Aug 21 '13 12:08

Behrad Farsi


People also ask

How many parameters can overload a function?

Overloaded functions: one unique parameter.

What is function overloading with example in C++?

Function overloading is a feature of object-oriented programming where two or more functions can have the same name but different parameters. When a function name is overloaded with different jobs it is called Function Overloading.

What is function overloading explain through an example?

Function overloading is a C++ programming feature that allows us to have more than one function having same name but different parameter list, when I say parameter list, it means the data type and sequence of the parameters, for example the parameters list of a function myfuncn(int a, float b) is (int, float) which is ...


2 Answers

A List<string> is not a List<object>; however, List<string> is an object - so it makes perfect sense to choose that overload. Try instead:

public static void Log<T>(IList<T> objects)
{
    foreach (var obj in objects)
    {
        Console.WriteLine(obj);
    }
}  

or even:

public static void Log<T>(IEnumerable<T> objects)
{
    foreach (var obj in objects)
    {
        Console.WriteLine(obj);
    }
}  

You might also like:

public static void Log(params object[] objects)
{
    foreach (var obj in objects)
    {
        Console.WriteLine(obj);
    }
}

which can be used as:

Log("Test","Test2");
like image 108
Marc Gravell Avatar answered Oct 22 '22 09:10

Marc Gravell


A variation on Marc Gravell's answer:

public static void Log(IReadOnlyList<object> objects)
{
    foreach (var obj in objects)
    {
        Console.WriteLine(obj);
    }
}

This doesn't add anything to this particular example, but if you wanted to use indexed access to the collection like you could with a List<T>, this lets you do that in a way that IEnumerable<object> doesn't. (And yes, there's a LINQ operator for indexed access of enumerables, but it's clumsy, and may also be horribly slow. IReadOnlyList<object> is useful if you want to make it clear that your method requires efficient indexed access.)

Like Marc's version that uses IEnumerable<object> as the argument type, this exploits covariance - unlike List<T>, T is covariant in IEnumerable<T> and in IReadOnlyList<T>. That means that because string is an object, an IEnumerable<string> is an IEnumerable<object>, and likewise, IReadOnlyList<string> is an IReadOnlyList<object>.

The read-only nature of both interfaces is important. The whole reason your original example fails is that List<T> supports both reading and writing - if you pass me a List<object> I can add anything to it - a string, a Giraffe or whatever I like. That's why a List<string> is not an acceptable substitute for a List<object> - I can't add a Giraffe to a List<string>, even though I can add one to a List<object>. But because IEnumerable<T> and IReadOnlyList<T> do not allow objects to be added to the collections they represent, all that matter is what you can get out, not what you can put in. Anything that comes out of a collection that contains only string objects will be an object because everything's an object.

And yes, I know your original code didn't attempt to add anything to the list, but that doesn't matter - all C# cares about in this case is how the function signature looks. And by specifying IReadOnlyList<object> you are making clear that you will never attempt to modify the list, at which point C# knows it's OK to pass the List<string>.

like image 20
Ian Griffiths Avatar answered Oct 22 '22 09:10

Ian Griffiths