아래처럼 코딩하면

public Form1()
{
    InitializeComponent();

    Parallel.For(0, 100, (i) => Run(i));
}


private void Run(int i)
{
    Console.WriteLine(i.ToString());
}

100개의 쓰레드가 생성되어 동시에 Run 메서드를 실행하게 됩니다.

결과

0
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
37
38
39
40
41
42
43
44
45
46
47
48
36
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
3
4
5
6
7
8
9
10
11
97
98
99
49
50
51
52
53
54
55
56
57
58
59
1
2

 

쓰레드로 전역 변수를 핸들링 하고자 할때 락을 거는 등의 번거러운 작업이 필요합니다.

하지만 System.Collections.Concurrent 에 속하는 네임스페이스에 병렬작업을 위한 것들이 들어있습니다.

그중에 제가 많이 쓰는 Dictionary 입니다.

 

ConcurrentDictionary<TKey, TValue> 를 이용하게되면 번거롭게 lock 를 거는 일이 필요없습니다.

MSDN - 여러 개의 스레드에서 동시에 액세스할 수 있는 키/값 쌍의 스레드로부터 안전한 컬렉션을 나타냅니다.

 

쓰레드의 안전성을 유지하며 다중 쓰레드의 동시성 읽기/쓰기를 지원하고, 쓰레드의 안정적인 반복 처리 또한 허용합니다.

 

사용방법이 약간 다르니 사용방법은 아래 링크로~

http://msdn.microsoft.com/ko-kr/library/dd997369(v=vs.110).aspx

namespace DictionaryHowTo
{
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;

    // The type of the Value to store in the dictionary:
    class CityInfo : IEqualityComparer<CityInfo>
    {
        public string Name { get; set; }
        public DateTime lastQueryDate { get; set; }
        public decimal Longitude { get; set; }
        public decimal Latitude { get; set; }
        public int[] RecentHighTemperatures { get; set; }

        public CityInfo(string name, decimal longitude, decimal latitude, int[] temps)
        {
            Name = name;
            lastQueryDate = DateTime.Now;
            Longitude = longitude;
            Latitude = latitude;
            RecentHighTemperatures = temps;
        }

        public CityInfo()
        {
        }

        public CityInfo(string key)
        {
            Name = key;
            // MaxValue means "not initialized"
            Longitude = Decimal.MaxValue;
            Latitude = Decimal.MaxValue;
            lastQueryDate = DateTime.Now;
            RecentHighTemperatures = new int[] { 0 };

        }
        public bool Equals(CityInfo x, CityInfo y)
        {
            return x.Name == y.Name && x.Longitude == y.Longitude && x.Latitude == y.Latitude;
        }

        public int GetHashCode(CityInfo obj)
        {
            CityInfo ci = (CityInfo)obj;
            return ci.Name.GetHashCode();
        }
    }

    class Program
    {
        // Create a new concurrent dictionary.
        static ConcurrentDictionary<string, CityInfo> cities = new ConcurrentDictionary<string, CityInfo>();

        static void Main(string[] args)
        {
            CityInfo[] data =
            {
                new CityInfo(){ Name = "Boston", Latitude = 42.358769M, Longitude = -71.057806M, RecentHighTemperatures = new int[] {56, 51, 52, 58, 65, 56,53}},
                new CityInfo(){ Name = "Miami", Latitude = 25.780833M, Longitude = -80.195556M, RecentHighTemperatures = new int[] {86,87,88,87,85,85,86}},
                new CityInfo(){ Name = "Los Angeles", Latitude = 34.05M, Longitude = -118.25M, RecentHighTemperatures =   new int[] {67,68,69,73,79,78,78}},
                new CityInfo(){ Name = "Seattle", Latitude = 47.609722M, Longitude =  -122.333056M, RecentHighTemperatures =   new int[] {49,50,53,47,52,52,51}},
                new CityInfo(){ Name = "Toronto", Latitude = 43.716589M, Longitude = -79.340686M, RecentHighTemperatures =   new int[] {53,57, 51,52,56,55,50}},
                new CityInfo(){ Name = "Mexico City", Latitude = 19.432736M, Longitude = -99.133253M, RecentHighTemperatures =   new int[] {72,68,73,77,76,74,73}},
                new CityInfo(){ Name = "Rio de Janiero", Latitude = -22.908333M, Longitude = -43.196389M, RecentHighTemperatures =   new int[] {72,68,73,82,84,78,84}},
                new CityInfo(){ Name = "Quito", Latitude = -0.25M, Longitude = -78.583333M, RecentHighTemperatures =   new int[] {71,69,70,66,65,64,61}}
            };

            // Add some key/value pairs from multiple threads.
            Task[] tasks = new Task[2];

            tasks[0] = Task.Run(() =>
            {
                for (int i = 0; i < 2; i++)
                {
                    if (cities.TryAdd(data[i].Name, data[i]))
                        Console.WriteLine("Added {0} on thread {1}", data[i],
                            Thread.CurrentThread.ManagedThreadId);
                    else
                        Console.WriteLine("Could not add {0}", data[i]);
                }
            });

            tasks[1] = Task.Run(() =>
            {
                for (int i = 2; i < data.Length; i++)
                {
                    if (cities.TryAdd(data[i].Name, data[i]))
                        Console.WriteLine("Added {0} on thread {1}", data[i],
                            Thread.CurrentThread.ManagedThreadId);
                    else
                        Console.WriteLine("Could not add {0}", data[i]);
                }
            });

            // Output results so far.
            Task.WaitAll(tasks);

            // Enumerate collection from the app main thread.
            // Note that ConcurrentDictionary is the one concurrent collection
            // that does not support thread-safe enumeration.
            foreach (var city in cities)
            {
                Console.WriteLine("{0} has been added.", city.Key);
            }

            AddOrUpdateWithoutRetrieving();
            RetrieveValueOrAdd();
            RetrieveAndUpdateOrAdd(); 

            Console.WriteLine("Press any key.");
            Console.ReadKey();
        }

        // This method shows how to add key-value pairs to the dictionary
        // in scenarios where the key might already exist.
        private static void AddOrUpdateWithoutRetrieving()
        {
            // Sometime later. We receive new data from some source.
            CityInfo ci = new CityInfo() { Name = "Toronto",
                                            Latitude = 43.716589M,
                                            Longitude = -79.340686M,
                                            RecentHighTemperatures = new int[] { 54, 59, 67, 82, 87, 55, -14 } };

            // Try to add data. If it doesn't exist, the object ci is added. If it does
            // already exist, update existingVal according to the custom logic in the
            // delegate.
            cities.AddOrUpdate(ci.Name, ci,
                (key, existingVal) =>
                {
                    // If this delegate is invoked, then the key already exists.
                    // Here we make sure the city really is the same city we already have.
                    // (Support for multiple cities of the same name is left as an exercise for the reader.)
                    if (ci != existingVal)
                        throw new ArgumentException("Duplicate city names are not allowed: {0}.", ci.Name);

                    // The only updatable fields are the temerature array and lastQueryDate.
                    existingVal.lastQueryDate = DateTime.Now;
                    existingVal.RecentHighTemperatures = ci.RecentHighTemperatures;
                    return existingVal;
                });

            // Verify that the dictionary contains the new or updated data.
            Console.Write("Most recent high temperatures for {0} are: ", cities[ci.Name].Name);
            int[] temps = cities[ci.Name].RecentHighTemperatures;
            foreach (var temp in temps) Console.Write("{0}, ", temp);
            Console.WriteLine();
        }

        // This method shows how to use data and ensure that it has been
        // added to the dictionary.
        private static void RetrieveValueOrAdd()
        {
            string searchKey = "Caracas";
            CityInfo retrievedValue = null;

            try
            {
                retrievedValue = cities.GetOrAdd(searchKey, GetDataForCity(searchKey));
            }
            catch (ArgumentException e)
            {
                Console.WriteLine(e.Message);
            }

            // Use the data.
            if (retrievedValue != null)
            {
                Console.Write("Most recent high temperatures for {0} are: ", retrievedValue.Name);
                int[] temps = cities[retrievedValue.Name].RecentHighTemperatures;
                foreach (var temp in temps) Console.Write("{0}, ", temp);
            }
            Console.WriteLine();
        }




        // This method shows how to retrieve a value from the dictionary,
        // when you expect that the key/value pair already exists,
        // and then possibly update the dictionary with a new value for the key.
        private static void RetrieveAndUpdateOrAdd()
        {
            CityInfo retrievedValue;
            string searchKey = "Buenos Aires";

            if (cities.TryGetValue(searchKey, out retrievedValue))
            {
                // use the data
                Console.Write("Most recent high temperatures for {0} are: ", retrievedValue.Name);
                int[] temps = retrievedValue.RecentHighTemperatures;
                foreach (var temp in temps) Console.Write("{0}, ", temp);

                // Make a copy of the data. Our object will update its lastQueryDate automatically.
                CityInfo newValue = new CityInfo(retrievedValue.Name,
                                                retrievedValue.Longitude,
                                                retrievedValue.Latitude,
                                                retrievedValue.RecentHighTemperatures);

                // Replace the old value with the new value.
                if (!cities.TryUpdate(searchKey, retrievedValue, newValue))
                {
                    //The data was not updated. Log error, throw exception, etc.
                    Console.WriteLine("Could not update {0}", retrievedValue.Name);
                }
            }
            else
            {
                // Add the new key and value. Here we call a method to retrieve
                // the data. Another option is to add a default value here and
                // update with real data later on some other thread.
                CityInfo newValue = GetDataForCity(searchKey);
                if( cities.TryAdd(searchKey, newValue))
                {
                    // use the data
                    Console.Write("Most recent high temperatures for {0} are: ", newValue.Name);
                    int[] temps = newValue.RecentHighTemperatures;
                    foreach (var temp in temps) Console.Write("{0}, ", temp);
                }
                else
                    Console.WriteLine("Unable to add data for {0}", searchKey);
            }
        }

        //Assume this method knows how to find long/lat/temp info for any specified city.
        static CityInfo GetDataForCity(string name)
        {
            // Real implementation left as exercise for the reader.
            if (String.CompareOrdinal(name, "Caracas") == 0)
                return new CityInfo() { Name = "Caracas",
                                        Longitude = 10.5M,
                                        Latitude = -66.916667M,
                                        RecentHighTemperatures = new int[] { 91, 89, 91, 91, 87, 90, 91 } };
            else if (String.CompareOrdinal(name, "Buenos Aires") == 0)
                return new CityInfo() { Name = "Buenos Aires",
                                        Longitude = -34.61M,
                                        Latitude = -58.369997M,
                                        RecentHighTemperatures = new int[] { 80, 86, 89, 91, 84, 86, 88 } };
            else
                throw new ArgumentException("Cannot find any data for {0}", name);
        }
    }
}

* 참고

http://msdn.microsoft.com/ko-kr/library/dd287191(v=vs.110).aspx

 

동적 구현시 유용하게 사용되는 것으로

여러 인터페이스의 명시적 구현을 갖고 있으며 아래는 IDictionary 타입을 예시로 보여준것입니다.

아래에서 보시면 아시겠지만 워래 IDctionary 인터페이스는 이름을 사용해 객체를 다루는 방식이지만

동적타이핑을 통해 이들 이름을 속성으로 사용할 수 있습니다.

 

dynamic expando = new ExpandoObject();

IDictionary<string, object> dic = expando;
expando.First = "A";
Console.WriteLine(dic["First"]);

dic.Add("Second","B");
Console.WriteLine(expando.Second); 

결과

A

B

 

아래처럼 메서드인 처럼 사용할 수도 있습니다.

dynamic expando2 = new ExpandoObject();
expando2.AddOne = (Func<int, int>)(x => x + 1);
Console.WriteLine(expando2.AddOne(10));


결과

11

 

'C#' 카테고리의 다른 글

(C#) 병렬처리 테스트 방법  (0) 2017.09.20
(.NET) ConcurrentDictionary<TKey, TValue>  (0) 2017.09.17
(.NET) ExpandoObject  (0) 2017.09.17
(Linq) PLINQ(병렬 LINQ)  (0) 2017.09.17
(.NET) null 값 미리 체크하기  (0) 2017.09.17
윈폼 컨트롤 비동기로 다루기 (MethodInvoker)  (0) 2017.08.24
static Random r = new Random();

static int ObtainLengthSlowly(string name)
{
    Thread.Sleep(r.Next(1000));
    return name.Length;

}

 

// 아래 AsParallel 로 인해 6개의 쓰레드 까지 나뉘어 작업이 된다.

string[] names= {"Jun","Kayoung","Hadom","Jeae","Dongsuk"};
var queryPlinq = from name in names.AsParallel()
            select ObtainLengthSlowly(name);

 

foreach (int length in queryPlinq)
{
    Console.WriteLine(length);
}

위 결과는 순서 대로가 아닌 아래와 같은 결과가 나온다.

7
4
5
3

 

// AsParallel 을 제거한 결과는 순서대로 출력된다.

var queryPlinq = from name in names
            select ObtainLengthSlowly(name);

 

foreach (int length in queryPlinq)
{
    Console.WriteLine(length);
}

 

결과

3
7
5
4
7

 

        private dynamic SafeField(Func<dynamicfunc)
        {
            try
            {
                return func();
            }
            catch (System.NullReferenceException ex)             

            {

                 return "(Not set)";
            }
            catch (System.InvalidOperationException ex)

             {

                //LINQ 시퀀스에 요소가 없습니다.
                //if(ex.Message == "시퀀스에 요소가 없습니다.") .... todo?
                return "(Not data)";
            }
            catch (System.Exception ex)
            {
                return null;
            }
        }

 

사용법

txtREQUIREMENT.Text = SafeField(() => data.REQUIREMENT.NAME);

 

Task 나 Thread 내부에서 디자인단의 컨트롤의 내용을 변경하려면

Invoke 를 쓰면서 작업을 해줘야하는데

좀 쉽게 할수 있는 방법이 있어 공유합니다.

아시는 분은 패스~

 this.Invoke(new MethodInvoker(
                 delegate()
                 {
                     // 변경하고자 하는 작업을 코딩합니다.
                      this.progressbar.value = 40;
                      this.progressbarLabel.Text ="40";
                 }
                 )
            );
public enum AnimationType
    {
        Custom = 0,
        Rotate = 1,
        HorizSlide = 2,
        VertSlide = 3,
        Scale = 4,
        ScaleAndRotate = 5,
        HorizSlideAndRotate = 6,
        ScaleAndHorizSlide = 7,
        Transparent = 8,
        Leaf = 9,
        Mosaic = 10,
        Particles = 11,
        VertBlind = 12,
        HorizBlind = 13
    }

위와 같은 enum type 의 내용을 combobox 의 데이터로 사용하고 싶을 때

아래 처럼 코딩합니다.

this.aniComboBox.DataSource = Enum.GetValues(typeof(AnimationType));

 

선택한 값의 내용을 다시 enum type 에 맞게 가져오려면 아래처럼 코딩합니다.

AnimationType status;
Enum.TryParse<AnimationType>(this.aniComboBox.SelectedValue.ToString(), out status);

FormBorderStyle 을 None 으로 하게되면 전체 창의 크기를 변경할수 없게됩니다.

이를 변경가능하도록 하기위해 찾은 코드입니다.

Win32 API 를 이용한 방법입니다.

대략 순서는 아래와 같습니다.

1. Win32 API를 사용해서 현재 Form Window Window Style을 가져오기

2. WS_CAPTION 스타일 제거

3. WS_BORDER 스타일 추가

4. Win32 API를 사용해서 변경한 Window Style 재설정

아래내용을 전역으로 선언해주고

        [Flags]
        public enum WindowStyle
        {
            WS_OVERLAPPED = 0x00000000,
            WS_POPUP = -2147483648, //0x80000000,
            WS_CHILD = 0x40000000,
            WS_MINIMIZE = 0x20000000,
            WS_VISIBLE = 0x10000000,
            WS_DISABLED = 0x08000000,
            WS_CLIPSIBLINGS = 0x04000000,
            WS_CLIPCHILDREN = 0x02000000,
            WS_MAXIMIZE = 0x01000000,
            WS_CAPTION = 0x00C00000,
            WS_BORDER = 0x00800000,
            WS_DLGFRAME = 0x00400000,
            WS_VSCROLL = 0x00200000,
            WS_HSCROLL = 0x00100000,
            WS_SYSMENU = 0x00080000,
            WS_THICKFRAME = 0x00040000,
            WS_GROUP = 0x00020000,
            WS_TABSTOP = 0x00010000,
            WS_MINIMIZEBOX = 0x00020000,
            WS_MAXIMIZEBOX = 0x00010000,
            WS_TILED = WS_OVERLAPPED,
            WS_ICONIC = WS_MINIMIZE,
            WS_SIZEBOX = WS_THICKFRAME,
            WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW,
            WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
                        WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),
            WS_POPUPWINDOW = (WS_POPUP | WS_BORDER | WS_SYSMENU),
            WS_CHILDWINDOW = (WS_CHILD)
        }

        private const int GWL_STYLE = -16;

        [DllImport("user32.dll")]
        public static extern Int32 GetWindowLong(IntPtr hWnd, Int32 Offset);

        [DllImport("user32.dll")]
        public static extern Int32 SetWindowLong(IntPtr hWnd, Int32 Offset, Int32 newLong);

Form_Load 이벤트에 아래 내용을 추가합니다.

        private void Form1_Load(object sender, EventArgs e)
        {
            int style = GetWindowLong(this.Handle, GWL_STYLE);

            WindowStyle myStyle = (WindowStyle)style;
            myStyle = myStyle & ~WindowStyle.WS_CAPTION;
            myStyle = myStyle | WindowStyle.WS_BORDER;

            style = SetWindowLong(this.Handle, GWL_STYLE, (int)myStyle);
        }

그런데 불행하게도 완벽하지는 않네요 참고만 해주세요^^;

 

참고

http://blog.naver.com/saltynut/120042208214

리플렉터가 좋긴한데 유료화가 되면서 매번 PC 변경시 Crack 하여 써왔다

귀찮기도 하고 파일을 구하기도 힘들고.. 자꾸 Windows Defender 가 crack 파일을 자워버린다.;;

그리고 언제부턴가 이런 저런 crack 구하느라 시간 보내느니

적당한 가격이면 그냥 사서 쓰는게 마음이 편해서 원만하면 사서 쓰려고한다.

리플렉터도 그리 비싸진 않아 사려고 알아보다가.. 리플렉터 외에도 다른 좋은 툴들이 있다는걸 알고 살필요가 없어졌다.

여기서 소개할 디컴파일러는 두가지로 모두 무료다.

( 누군가는 GitHub에도 소스까지 공개하며 디컴파일러를 만들어 놨다..;;  https://github.com/0xd4d/dnSpy)

 

1. dotPeek (닷픽)

JET BRAINS 에서 만들어진 것으로 이 제품 외에도 여러 제품들이 있다.

(언젠가 나도 이렇게 여러 제품을 만들날이 올까..)

http://www.jetbrains.com/decompiler/download/

설치하면 아래와 같은 화면이 나타난다.

리플렉터도 그랬지만 이제품도 Visual Studio 에 add in 하여 사용할수 있다.

ReSharper 가 그것으로 개인적으로 추천하지는 않는다. (지극히 개인적임)

이전에 리플렉터를 그렇게 써봤는데 너무 느려서 지웠다.

실행해보니 디자인도 깔끔하다 Visual Studio 인줄...

역시 코드 난독화가 되어있다. ㅋ

 

2. JustDecompile

Telerik 에서 만든것으로 이회사는 처음에 피들러 때문에 알게된 회사인데 현재는 정말 많이 커졌다.

특히나 Xamarin 공부하면서 이쪽 컨트롤들을 많이 추천하고 있고 그만큼 사용도 많이하고 있는것 같다.

http://www.telerik.com/products/decompiler.aspx

설치를 해보자.

Telerik 에서 제공되는 많은 제품들도 동시에 설치가 가능하도록 되어있다.

그런데 쓸만한 것들?은 모두 유료고 비싸다.. 다행히 디컴파일러는 무료.

제품을 설치하려면 계정을 만들어야한다..;;

아래는 실행화면..

 

두개 동시에 써보니 dotPeek 이 더 기능도 많고 좋은것 같다. 디자인도 깔끔하고.. 계정도 안만들어도 되고..

무엇보다도 아래 코드처럼 if 문 디컴파일이 dotPeek 좀더 고급스럽게? 디컴파일이 된다.

dotPeek

    private void method_0()
    {
      int r = (int) this.BackColor.R;
      int red = r - this.int_1 < 0 ? 0 : r - this.int_1;
      int g = (int) this.BackColor.G;
      int green = g - this.int_1 < 0 ? 0 : g - this.int_1;
      int b = (int) this.BackColor.B;
      int blue = b - this.int_1 < 0 ? 0 : b - this.int_1;
      this.BottomLine.BackColor = Color.FromArgb(red, green, blue);
    }

JustDecompile

        private void method_0()
        {
            int r = this.BackColor.R;
            if (r - this.int_1 < 0)
            {
                r = 0;
            }
            else
            {
                r -= this.int_1;
            }
            int g = this.BackColor.G;
            if (g - this.int_1 < 0)
            {
                g = 0;
            }
            else
            {
                g -= this.int_1;
            }
            int b = this.BackColor.B;
            if (b - this.int_1 < 0)
            {
                b = 0;
            }
            else
            {
                b -= this.int_1;
            }
            this.BottomLine.BackColor = Color.FromArgb(r, g, b);
        }

역시 둘다 난독화는 어쩔수 없다. ^^

 

 

FomBorderStyle 이  None 인 경우 폼은 마우스로 움직일수가 없다.

그래서 찾아보니 아래처럼 하면 폼을 마우스로 움직일 수가 있다.

만약 Form 위에 Panel 이 올려져 있다면 Panel 에 이벤트를 주면된다.

using System.Runtime.InteropServices;

..... 

public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();

......
private void Form_MouseDown(object sender, MouseEventArgs e)
{
    ReleaseCapture();
    SendMessage(this.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}

 

+ Recent posts