-1

Ok here i have created a program that does multiple copy and adding text into files, tho its run time what i have come up with is a list_ that stores loads of keys then prints back at the end of the process instead of having loads of message boxes coming up this is what i have

the list class.

   public class Messageresult : Weaons
{

    private List<string> elfenliedtopfan5 = new List<string>();
    public List<string> _Message

    {
        get { return elfenliedtopfan5; }
        set { elfenliedtopfan5 = value; }
    }

}

and in multiple of classes i call this like so

    public void ShowMessage()
    {
             elfy1 = new Messageresult();
            //MessageBox.Show(elfy1._Message.ToString());

            update();
            refreshlist();
            var message = string.Join(Environment.NewLine, elfy1._Message);
            MessageBox.Show(message + Environment.NewLine +
                createa + Environment.NewLine + results);
            elfy1._Message.Clear();  }

so this is what i use in multiple different classes and i use inheritance tis class above is called weapons. and all my other classes inherit weapons but

the issue im having is in certain classes like my thundergun class when i call this.

 public void cliantfx()
    {
        elfy1 = new Messageresult();
        string path = modcliant;
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
            File.Copy(Properties.Settings.Default.root + "//raw//clientscripts//" + ModName + ".csc", path + ModName + ".csc");
            MessageBox.Show(path);
        }


        if (File.Exists(path + ModName + ".csc"))
        {


            using (StreamReader elfenliedtopfan6 = new StreamReader((path + ModName + ".csc")))
            {
                string elfenliedtopfan6_program = elfenliedtopfan6.ReadToEnd();
                if (elfenliedtopfan6_program.Contains(@"clientscripts\_thundergun::init();"))
                {
                    //MessageBox.Show(@"clientscripts\_thundergun::init();" + "Already Added:");
                    refreshlist();
                    elfy1._Message.Add("clientscripts\\_thundergun::init();" + "Already Added:");

                }

                if (!elfenliedtopfan6_program.Contains(@"clientscripts\_thundergun::init();"))
                {

                    elfenliedtopfan6.Dispose();
                    if (File.Exists(path + ModName + ".csc"))
                    {
                        {
                            string s = Environment.NewLine
                                       + @"    clientscripts\_thundergun::init();";

                            string file = path + ModName + ".csc";
                            List<string> lines = new List<string>(System.IO.File.ReadAllLines(file));
                            int index = lines.FindLastIndex(item => item.Contains(@"clientscripts\_zombiemode_tesla::init();"));
                            if (index != -1)
                            {
                                lines.Insert(index + 1, s);//""
                            }
                            System.IO.File.WriteAllLines(file, lines);

                            MessageBox.Show("Added: " + s + "To " + ModName);


                        }

                    }

and as you can see elfy1._message.Add("text here....")

is called in weapons but when it executes tho this it just gives a blank message box yet when i execute weapons_gsc it works perfectly fine

and i use the same call methord and the showmessage() function in weapons

yet in sounds class and thundergun class it wont update it or display once its executed

so im not sure how i would go about this.

because it works perfectly fine for weapons_gsc image below show results

image of it working for weapons_gsc and weapons

the sound one you see at the end i had to make a propeties.setting.default.results

and made it = to the sound alais one only way i could get it to display the results all in one message box.

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
  • 1
    Every time you write `new Messageresult();`, you are creating a new instance of this class. So this is not a "global list", even its members are not static, and it only exists until you create a new instance. If you only have a single thread, just mark the field `readonly` and instantiate it once, in the constructor or field initializer. – vgru Feb 17 '16 at 12:49
  • in the class thundergun i have about 7 threads i just picked that one as a example as that class is a big class so did not want to post the whole thing on here and how would i work the readonly ( as my main class is weapons.cs and is inherited by all other classes. – Saito Hiraga Feb 17 '16 at 12:55
  • This class has no synchronization at all, so it's not safe for multithreaded access. Are you sure this should be a *field*? Because you either: 1) want a single instance which can be used by multiple threads concurrently (in which case you need a **single threadsafe instance**, or 2) want each method/thread to have a separate **local variable** which will be dumped at the end of that scope. Right now, you are setting the `elfy1` field to point to a new instance (at the beginning of some method), then mutating its list (from some other methods), and finally reading its contents from somewhere. – vgru Feb 17 '16 at 13:15
  • form what you said the first one is what im needing basicly i want to add a line to the list each process it does for my program then at the end print out all the things that have been added or are already added thats, i want to do it but it just dont seem to work like that and i never hurd of single threadsafe instance before – Saito Hiraga Feb 17 '16 at 13:59

1 Answers1

0

Before going further, I would like to suggest that you take a slightly different approach; i.e. I see no reason why you wouldn't simply use a logging framework like log4net and add a custom appender which would redirect messages to a text box, along with a textual log file. When your app crashes, having a log is invaluable for troubleshooting.

Synchronizing access to the logger class

Nevertheless, if you need to write these log messages from multiple threads, then you need to synchronize access to the Add method. You shouldn't expose the list as a public property, but instead create methods which will be synchronized:

public class Logger
{
    private readonly object _lock = new object();
    private readonly List<string> _messages = new List<string>();

    public void Append(string message)
    {
        // locking ensures that only a single thread can enter this block
        lock (_lock)
        {
            _messages.Add(message);
        }
    }

    // since we are locking this method too, we can be sure that
    // we will join messages into a single string and clear the list
    // without being interrupted (atomically)
    public string Merge()
    {
        lock (_lock)
        {
            // now you are sure you won't lose any data, because
            // it's impossible for other threads to append to _messages
            // between joining and clearing it

            var result = string.Join(Environment.NewLine, _messages);
            _messages.Clear();
            return result;
        }
    }
}

Having something like this in place, you need to ensure that you don't create a new instance of this class on each access. This means that your class should create the "logger" only once:

public class SomeOtherClass
{
    // once you add the 'readonly' keyword, compiler        
    // won't let you accidentally create another instance
    private readonly Logger _logger = new Logger();

    public void SomeMethod()
    {
        // _logger = new Logger(); // <-- this will not compile

        _logger.Append("Some message");
    }

    public void SomeOtherMethod()
    {
        MessageBox.Show(_logger.Merge());
    }
}

Making the class a singleton

Alternatively, you may want to make the logger class a singleton (in most cases not the best idea, but if this is a one time small project, it might simplify things):

public class Logger
{    
#region Singleton pattern

    // this is the static one-and-only logger instance, alive
    // throughout the lifetime of your application
    private static readonly Logger _instance = new Logger();
    public static Logger Instance
    {
        get { return _instance; }
    }

    // private empty constructor is here to ensure 
    // that you can only access this class through the
    // Logger.Instance static property
    private Logger() { }

#endregion

    private readonly object _lock = new object();
    private readonly List<string> _messages = new List<string>(); 
    public void Append(string message)
    {
        lock (_lock)
            _messages.Add(message);
    }

    public string Merge()
    {
        lock (_lock)
        {
            var result = string.Join(Environment.NewLine, _messages);
            _messages.Clear();
            return result;
        }
    }
}

In this case, you wouldn't need to instantiate the logger class at all, and all your classes can only access a single instance, using multiple threads:

public class SomeOtherClass
{
    public void SomeMethod()
    {
        Logger.Instance.Append("Some message");
    }

    public void SomeOtherMethod()
    {
        MessageBox.Show(Logger.Instance.Merge());
    }
}
Community
  • 1
  • 1
vgru
  • 49,838
  • 16
  • 120
  • 201
  • 1
    Thank you so much really thank you it works perfectly honestly your a life saver :) [WORKING RESAULT] (https://winpic.co/46M76a2f16ef8.png) – Saito Hiraga Feb 18 '16 at 14:57