4

I have an example code like this:

public class SimpleLogger
{
    private static SimpleLogger logger;
    private string path = null;

    protected SimpleLogger(string path)
    {
        this.path = path;
    }

    public static SimpleLogger Instance(string path)
    {
        if (logger == null)
        {
            logger = new SimpleLogger(path);
        }
        return logger;
    }

    public static void Info(string info)
    {
        string path = $"{logger.path}{DateTime.Now.ToShortDateString()}_Info.txt";
        using (StreamWriter writer = new StreamWriter(path))
        {
            writer.WriteLine($"{DateTime.Now} - {info}");
        }
    }
}

and when I call:

SimpleLogger.Instance("path").Info("info");

There's an error:
member cannot be accessed with an instance reference qualify it with a type name instead static method

But I DO use type name, don't I?

But when I call it like this:

SimpleLogger.Instance("path");
SimpleLogger.Info("info");  

it actually does work fine.

To make it work inline I have to make Info method non-static and then inline call work also fine. Why is that? I don't understand the mechanism here. Can someone explain? Is it beacuse Instance method returns SimpleLogger object and then info requires to be non-static to be able to work on an instance rather than a type?

Mike
  • 151
  • 1
  • 4
  • 14
  • 1
    Mind: This Singleton implementation is not at all ThreadSafe. And I recommend using a logging Framework like Serilog, NLog or log4net instead. They are commonly used, tested and easy to configure. – Fildor Sep 04 '18 at 10:07
  • 1
    And even if the singleton implementation is dropped: it is still not thread safe. – Stefan Sep 04 '18 at 10:08
  • 1
    Please think twice about using the singleton anti-pattern. For reference [StackOverflow Link](https://stackoverflow.com/questions/12755539/why-is-singleton-considered-an-anti-pattern) and [Software Engineering Link](https://softwareengineering.stackexchange.com/questions/252/when-is-singleton-appropriate). – nvoigt Sep 04 '18 at 10:10
  • Sory guys, this is not a question about Singleton pros and cons. – Mike Sep 04 '18 at 10:41

4 Answers4

7

In C#, instance methods can only be called on an instance, whereas static methods can only be called on a class/struct itself.

Why can't you chain Info onto SimpleLogger.Instance()?

Because SimpleLogger.Instance(...) returns an instance of SimpleLogger, and you are trying to call a static method on the returned value. The returned value is an instance of SimpleLogger, so you can't call a static method on it.

By making Info non-static, you enable it to be called on an instance. Therefore, you can call it on the return value of Instance().

One reason for your confusion might be that you don't see the instance of SimpleLogger in your chain of methods, so to better illustrate the idea of chaining methods, this:

SimpleLogger.Instance("path").Info("info");

is equivalent to:

SimpleLogger logger = impleLogger.Instance("path");
logger.Info("info");

See the instance of SimpleLogger now?

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Ok, thanks for clearing that. I wasn't sure. I can't chain Info because I have an output code calling the class and I have to write a class implementation based on it (educational). Thanks for the answer. – Mike Sep 04 '18 at 10:44
5

Exactly as you wrote. You call static methods on the class, cannot call them on objects, and your Instance method returns concrete object of the SimpleLoggerclass. If you want chaining of the methods (ie. SimpleLogger.Instance("path").Info("info"); ), you'll have to change Info(string info) to non-static class. It makes more sense to have those methods be non-static, and make the class be Singleton

Caldazar
  • 2,801
  • 13
  • 21
2

When you're calling

SimpleLogger.Instance("path").Info("info");

the .Instance(...) is returning an instance of the SimpleLogger class. Calling .Info directly on that instance is causing this warning, because .Info(...) is defined as static.

You could rewrite .Info() like this:

public void Info(string info)
{
    string path = $"{this.path}{DateTime.Now.ToShortDateString()}_Info.txt";
    using (StreamWriter writer = new StreamWriter(path))
    {
        writer.WriteLine($"{DateTime.Now} - {info}");
    }
}

In this way, you can call

SimpleLogger.Instance("path").Info("info");

without the warning, but you cannot call this anymore:

SimpleLogger.Info("info");
Marc Brekoo
  • 576
  • 1
  • 10
  • 24
0

You are calling a static method from its instance. As I see, perhaps you are trying to create a Logger class as singleton patterns. Then you just make Info(string info) method to a non-static method:

    public class SimpleLogger
    {
        private static SimpleLogger logger;
        private string path = null;

        protected SimpleLogger(string path)
        {
            this.path = path;
        }

        public static SimpleLogger Instance(string path)
        {
            if (logger == null)
            {
                logger = new SimpleLogger(path);
            }

            return logger;
        }

        public void Info(string info)
        {
            string path = $"{logger.path}{DateTime.Now.ToShortDateString()}_Info.txt";

            using (StreamWriter writer = new StreamWriter(path))
            {
                writer.WriteLine($"{DateTime.Now} - {info}");
            }
        }
    }
Nhan Phan
  • 1,262
  • 1
  • 14
  • 32