#PARAN SILVERLIGHT#
  • Tistory
    • 관리자
    • 글쓰기
Carousel 01
Carousel 02
Previous Next

'PROGRAMING'에 해당되는 글 58건

  • 2019.11.22 Functional Programming in C#
  • 2017.11.03 WPF - Nuget package - PropertyChanged.Fody
  • 2017.09.05 Code Smell 에 관하여
  • 2017.02.16 Background worker - Test project with WPF
  • 2015.07.14 C# Basic 다시 공부
  • 2014.11.25 MVC4 Could not load type 'System.ServiceModel.Activation.HttpModule'
  • 2013.09.03 Lecture3 : Deploy Rails App through Haroku
  • 2013.09.03 Lecture2 : Version control with Git
  • 2013.09.03 Lecture1 : My First Rails Application
  • 2013.09.03 Tutorial 사이트 및 E-Book

Functional Programming in C#

PROGRAMING/C# 2019. 11. 22. 10:01



참고 post 

https://nearsoft.com/blog/functional-programming-concepts-applied-using-c/


http://hamidmosalla.com/2019/04/25/functional-programming-in-c-sharp-a-brief-guide/



---------------------------------------------------------------------------------------------

아래 내용은 https://www.youtube.com/watch?v=jnefwbiK11Q 를 참고해서 작성



- Mutable value를 사용하는 대신 , 새로 Imutable instance를 생성해서 변경


- 함수를 새로 만들어 호출하는 대신 Func를 사용하여 캡슐화


- 일급 함수 ,  함수를 파라미터로 받아들이고 , 리턴하는 함수


- Statement 내부 Mutable variable은 병렬처리 시에 문제를 일으키 소지가 있다.

  Express을 사용해서 부작용을 제거


- 일급함수는 function을 리턴하므로 Method chaining pattern이 가능


- Class 내부에 함수를 생성하지 말고 Extension Methods를 사용 , 많이 사용하자

 Interface를 수정하지 않아 구현이 편할 뿐만 아니라 Chaining pattern을 가능하게 함


- Mutable이므로 부작용을 일으킬 수 있으므로 Extra Temp Data list을 제거하자. 

  심지어 코드도 깔끔하다. 


- Data class를 새로 만들어 사용하기 보다 Tuple을 사용해서 Data structure를 구성


[Functional programming workshop#]

1. Statement 를 Expression로 변경 


2. Extension method(ToAlike)을 사용해서 expression을 사용


3. Get Score 함수를 Statement에서 expression으로 정의해서 Chaining을 가능하게



블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

WPF - Nuget package - PropertyChanged.Fody

PROGRAMING/C# 2017. 11. 3. 15:43

Property Change event 를 작성하지 않아도 이 이벤트가 fire될 수 있도록 한다. :)




[Nuget package 설치 전]

public string InitialQty
{
    get
    {
        return _initialQty;
    }
    set
    {
        if (value != _initialQty)
        {
            _initialQty = value;
            base.RaisePropertyChanged(m => m.InitialQty);
        }
    }
}

[Nuget package 설치 후]

public string InitialQty { get; set;}


BaseViewmodel에 AddINotifyPropertyChangedInterface attribute를 추가한다. 

BaseViewmodel를 상속받아 Viewmodel을 작성하면 된다. ^^

/// <summary>
/// A base view model that fires Property Changed events as needed
/// </summary>
[AddINotifyPropertyChangedInterface]
public class BaseViewModel : INotifyPropertyChanged
{
    /// <summary>
    /// The event that is fired when any child property changes its value
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
 
 
    /// <summary>
    /// Call this to fire a <see cref="PropertyChanged"/> event
    /// </summary>
    /// <param name="name"></param>
    public void OnPropertyChanged(string name)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}
public class MainWindowViewmodel : BaseViewModel
{


저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Code Smell 에 관하여

PROGRAMING 2017. 9. 5. 14:22

 

좋은 글이 있어 아래 블로그에서 퍼왔습니다. 문제시 삭제하겠습니다. 

http://rapapa.net/?p=2406

 높은 퀄러티의 코드를 유지하는 작업은 프로젝트가 중반 이후로 갈 수록 뼈저리게 중요함을 많이 느낀다. 막판 마감일이 다가오면 프로젝트의 버그를 잡거나 기능을 수정하는 데 온 시간들을 빼앗겨서 좋은 Code Quality를 유지하는 것이 더 어렵다. QA 혹은 QC를 진행한 후에는 조금 한숨을 돌린다고 치더라도, 그 때 Refactoring을 진행하는 것은 치카치카를 한 다음 밥을 먹는 것과 같을 것이다.
Code Smell 이란 개발자들 사이에서 쓰는 단어다. Wikipedia에 따르면 “any symptom in the source code of a program that possibly indicates a deeper problem”, 즉 더 큰 문제들이 있음을 가리키고 있을만한, 소스 코드 상의 증상들이다. 이건 버그와는 다른데, 버그는 딱 집어서 기능이 제대로 동작하지 않는 문제 이지만 Code Smell은 정상적인 기능 수행과는 무관하게 존재한다. Code Smell을 디자인 패턴과 밀접한 관련이 있는데, 잘못 설계된 디자인 패턴이나 전체적인 프로그램의 디자인 패턴을 해치는 특정한 구조들이라고 볼 수도 있다. Code Smell은 코드의 디자인적인 약점이며, 그로인해 개발을 느리게 만들고, 버그가 생기기 쉽게 한다.

따라서, Code Smell은 Refectoring과 밀접하게 연관되어 있다. Code Smell을 체크하여 Refectoring의 타임을 결정할 수 있고 Refectoring은 Code Smell들을 없애는 방향으로 작업하게 된다.

이 Code Smell을 잘 맡을 수 있는 개발자가 좋은 개발자임은 당연한 것이다. 또한, Code Smell의 개념을 잘 알고 있어서, 본인이 개발한 혹은 개발하고 있는 코드에서 Code Smell을 느낄 수 있는 개발자들이 더 좋은 코드를 만들어내는 도전을 받게 되는 것도 자연스럽다.

Code Smell의 예는 매우 다양한다. SO cofounder인 codinghorror 가 Code Smell에 대해서 쓴 글에서 그는 Code Smell의 예를 이렇게 든다.

클래스 내부적으로는

  •  Comment는 항상 What보다는 Why에 대해 적도록 노력해야한다. 또한, 기계를 향해 적는것이 아니라 사람을 향해 적는 것임을 잊지 말아야 하고, 코멘트가 필요 없는 구조와 Naming이 제일 좋으므로 꼭 필요한 건지 체크할 필요가 있다.
  •  짧은 메쏘드 이름이 읽기에도 이해하기에도 좋다. 너무 긴 메쏘드는 작은 메쏘드들로 분리하라.
  • 메쏘드의 파라미터들이 많으면 많을 수록 복잡도가 증가한다. 파라미터의 갯수를 제한하고, Object를 통해 넘겨라.
  • 소프트웨어 개발의 맹독은 중복되는 코드들이다. 코드 내에 가능한한 중복된 코드를 제거하고 가능한한 전체 소프트웨어를 중복 코드 없이 유일한 코드들로 채우도록 노력해야 한다.
  • 너무 거대해지는 Conditional logic을 멀리하라. 시간이 지남에 따라 조건 블락들이 너무 커지고 비대해질 경우 State나 Decorator 등의 접근을 통해 OOP 구조로 바꾸는 것을 고려하라.
  • 거의 같은데 약간씩 다른 코트들도 주효한 Code Smell이다. Generic이나 Interpreter로 대체하여 중복을 없내는 것을 고려하라.
  • 너무 비대한 클래스는 거대한 메쏘드와 같은 효과를 불러 일으킨다. 코드를 읽어 내기도, 이해하기도, 수정하기도 힘들다. 클래스 하나가 너무 많은 책임을 가지고 있는지 체크하라. 그렇다면 더 작은 클래스들로 분리시켜라.
  • 메쏘드 이름에 파라미터 타입을 넣지 마라. 타입은 언제든지 바뀔 수 있다.
  • 메쏘드 이름을 가지고 다른 개발자에게 무엇을 하는 메쏘드인지 설명하기 어렵다면 Rename을 하거나 재작성하라.
  • 표준 용어들을 써서 Naming하라. 가령 Open()이라는 메쏘드가 있으면 Close()가 존재할 것이다.
  • 사용하지 않는 코드는 무자비하게 지워버려라. 코드는 이미 소스 컨트롤 시스템에 커밋되어 있다.
  • 오늘 필요한 코드를 짜라. 대부분의 미래에 일어날 일을 대비하는 코드들은 쓸모없게 되는 경우가 허다하다.
  • 하나의 동작을 하는 코드는 전체 소스 코드 내에서 하나의 코드로만 존재해야 한다. 특정 동작에 대해서 약간 이상한 방법들이 다양하게 존재한다면 이 또한 중복 코드와 다를 것이 없다.
  • 파라미터로 오브젝트를 넘긴다면 일부를 사용하기보다 가능한 전부를 사용하는 것이 좋다. 필요 없는 필드를 없애라.

 
클래스와 클래스 간에서는

  • 두클래스가 내부적으로는 비슷하고 바깥에서 보기에는 달라보인다면 공통 Interface를 만들어서 공유하게 수정할 수 있다.
  • 수많은 기본 데이터 타입을 나열하여 클래스를 대체하지 말자. 데이터들이 충분히 복잡하고 많다면 그것들을 표현하는 Struct나 Class를 만들자.
  • 항상 두 데이터가 같이 따라다닌다면 Structure나 Class로 묶어주라.
  • 상속을 해놓고 상위 클래스의 메쏘드를 하나도 쓰지 않는다면 해당 상속은 필요 없지 않을까.
  • 클래스에서 외부로 드러난 부분인 Public을 공격적으로 줄여라. 가능한 public을 줄이는 것이 좋다.
  • 다른 클래스의 메쏘드를 많이 사용해야하는 메쏘드라면 그 다른 클래스로 옮기는 것이 좋지 않을까.
  • 클래스가 너무 많이 있는 것도 복잡도를 증가한다. 클래스를 만드는 것에는 적당한 내용과 무게감이 존재해야 한다.
  • 모든 작업을 Delegating 시키는 클래스는 존재의 이유가 불분명하다. 이러한 중간 클래스 혹은 Wrapper들을 없애라.
  • 시간이 가면 갈수록 해당 클래스의 주요 목적과는 크게 무관한 부분의 코드가 커지고 있다면 그 부분을 따로 떼어 내는 것을 고려하라.
  • 한개의 클래스의 변경이 다른 여러 클래스의 추가 변경으로 Chainning 형태로 이뤄져야할 경우 Refectoring을 하여 하나의 클래스 수정으로 가능하도록 변경하라.
  • 특정 기능이 빠진 라이브러리 자체를 바꿀 수 없다면 원하는 메쏘드만 따로 고립시키는 것을 고민하라.
  • 하나의 유의미한 작업을 하기 위해서 대여섯개의 클래스를 이용해야 한다면 너무 벌려 놓은 것이 아닌가 고민하고 디자인적으로 더 간단하게 만드는 법을 고민하라.
  • Code Smell을 잘 맡을 수 없는 개발자라면 본인이 무엇을 잘못 짜고 있는지 명확하게 알고 있지 못할 여지가 많다. 해당 동작의 기능만 구현된다면 아무런 문제를 제기하지 않는 개발 조직이 대부분이기 때문이다. 그리고 Bug의 경우에는 딱 집어서 무엇이 잘못되었다 라고 이야기할 수 있지만, Code Smell은 그 특성상 명백한 잘잘못을 지적하기 어려운 경우가 많다.

이런 것을 굳이 비유를 들자면 이렇다.
좋은 시민이란 그 국가에서 정해 놓은 법을 어기지 않는 시민이다. 이건 버그를 양산하지 않는 개발자가 좋은 개발자라는 말과 동일하다.
그러나, 정말 좋은 시민이란 준법은 기본적으로 지키되, 그 국가 법의 근본 정신과 그 법이 추구하는 궁극적인 인간상과 가장 닮아 있는 시민일 것이다.

단순히 버그가 없다고 해서 좋은 개발자라고 한다면 좋은 개발자는 코딩을 가장 적게하거나 가장 쉬운 부분을 코딩하는 개발자가 가장 좋은 개발자일 가능성이 높아진다. 그러나 좋은 개발자의 조건에 Code Smell을 일으키는 코드를 거의 만들지 않는 개발자라고 하면 그 기준은 한단계 더 높아지게 되고 정교하게 된다.

Code Smell에 대한 높은 이해는 높은 Software Quality와 직접적인 연관이 있다. 그러므로 좋은 개발자는 코드의 냄새를 잘 맡을 수 있어야 한다.



저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Background worker - Test project with WPF

PROGRAMING/C# 2017. 2. 16. 10:41

Head Frist c# 3rd Edition에 부록에 있는 Background worker 구현 (Progress bar update)

- Do work process

- Cancellation process

- report progress  


1. 쓰레드로 구현하지 않을 경우 , Progress bar가 진행하는 동안 Main process를 접근 불가 (check를 하지 않고 실행)

2. 쓰레드와 Time.Sleep을 구현하는 방법 보다 간단함 




[MainWindow.xml]

<Window x:Class="BackgroundWorkerTest.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:BackgroundWorkerTest"

        mc:Ignorable="d"

        Title="Background Worker Example" Height="150" Width="300">

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

        </Grid.RowDefinitions>


        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="*"></ColumnDefinition>

            <ColumnDefinition Width="*"></ColumnDefinition>

            <ColumnDefinition Width="*"></ColumnDefinition>

        </Grid.ColumnDefinitions>


        <CheckBox Name="useBackgroundWorkerCheckbox"  Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center"></CheckBox>

        <Label Grid.Column="1" Grid.ColumnSpan="2" Content="Use BackgroundWoker" HorizontalAlignment="Center" VerticalAlignment="Center"></Label>

        <Button  Name="goButton" Grid.Row="1" Grid.Column="0" Margin="3,3,3,3" Content="Go!" FontSize="10.667" Click="goButton_Click" IsEnabled="True"></Button>

        <Button  Name="cancelButton" Grid.Row="1" Grid.Column="1" Margin="3,3,3,3" Content="Cancel" FontSize="10.667" Click="cancelButton_Click" IsEnabled="True"  ></Button>

        <ProgressBar Grid.Row="2" Margin="3,3,3,3" Grid.ColumnSpan="3" Name="progressBar1"></ProgressBar>


        


    </Grid>

</Window>


[MainWindow.xaml.cs]

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;


namespace BackgroundWorkerTest

{

    /// <summary>

    /// Interaction logic for MainWindow.xaml

    /// </summary>

    public partial class MainWindow : Window

    {

        private readonly BackgroundWorker backgroundWorker1 = new BackgroundWorker();


        public MainWindow()

        {

            InitializeComponent();

            backgroundWorker1.WorkerSupportsCancellation = true;

            backgroundWorker1.WorkerReportsProgress = true;

            backgroundWorker1.DoWork += backgroundWorker1_DoWork;

            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;

            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;

        }


        //ui event

        private void goButton_Click(object sender, EventArgs e)

        {

            goButton.IsEnabled = false;


            if (!useBackgroundWorkerCheckbox.IsChecked == true)

            {

                // If we're not using the background worker, just start wasting CPU cycles

                for (int i = 1; i <= 100; i++)

                {

                    WasteCPUCycles();

                    progressBar1.Value = i;

                }

                goButton.IsEnabled = true;

            }

            else {

                // If the form's using the background worker, it enables the Cancel button.

                cancelButton.IsEnabled = true;


                // If we are using the background worker, use its RunWorkerAsync()

                // to tell it to start its work

                backgroundWorker1.RunWorkerAsync(new Guy("Bob", 37, 146));

            }

        }

        /// <summary>

        /// When the user clicks Cancel, call BackgroundWorker.CancelAsync() to send it a cancel message

        /// </summary>

        private void cancelButton_Click(object sender, EventArgs e)

        {

            // If the user clicks Cancel, it calls the BackgroundWorker's CancelAsync()

            // method to give it the message to cancel.

            backgroundWorker1.CancelAsync();

        }


        //background worker function

        /// <summary>

        /// The BackgroundWorker object runs its DoWork event handler in the background

        /// </summary>

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

        {

            // The e.Argument property returns the argument that was passed to RunWorkerAsync()

            Console.WriteLine("Background worker argument: " + (e.Argument ?? "null"));


            // Start wasting CPU cycles

            for (int i = 1; i <= 100; i++)

            {

                WasteCPUCycles();

                // Use the BackgroundWorker.ReportProgress method to report the % complete

                backgroundWorker1.ReportProgress(i);


                // If the BackgroundWorker.CancellationPending property is true, cancel

                if (backgroundWorker1.CancellationPending)

                {

                    Console.WriteLine("Cancelled");

                    break;

                }

            }

        }

        /// <summary>

        /// BackgroundWorker fires its ProgressChanged event when the worker thread reports progress

        /// </summary>

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

        {

            progressBar1.Value = e.ProgressPercentage;

        }

        /// <summary>

        /// BackgroundWorker fires its RunWorkerCompleted event when its work is done (or cancelled)

        /// </summary>

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

        {

            // When the work is complete, the RunWorkerCompleted event handler 

            // re-enables the Go! button and disables the Cancel button.

            goButton.IsEnabled = true;

            cancelButton.IsEnabled = false;

        }


        //other function

        /// <summary>

        /// Waste CPU cycles causing the program to slow down by doing calculations for 100ms

        /// </summary>

        private void WasteCPUCycles()

        {

            DateTime startTime = DateTime.Now;

            double value = Math.E;

            while (DateTime.Now < startTime.AddMilliseconds(100))

            {

                value /= Math.PI;

                value *= Math.Sqrt(2);

            }

        }

        /// <summary>

        /// Clicking the Go button starts wasting CPU cycles for 10 seconds

        /// </summary>




    }

}


- 아래 프로젝트(Viaual studio 2015에서 작성)

BackgroundWorkerTest.7z

- 실행 파일 

Release.7z


저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

C# Basic 다시 공부

PROGRAMING/C# 2015. 7. 14. 10:29

 공변성 반공변경 대한 자료를 찾다가 발견한 아래 사이트에서 C#을 복습할 있는 기회가 있어 포스팅


http://www.devbb.net/viewforum.php?f=38&sid=0ed08ea5ae039c4a56164f85650622c1




기본 할당과 변수 유효 범위

 

C#은 자동적으로 모든 멤버 변수를 안전한 기본 값 '0' 으로 설정한다.
하지만 메소드내 지역변수는 자동으로 기본 값이 할당되지 않기 때문에, 사용전에 초기화가 필요하다.

Code:

using System;
class DefaultValueTester
{
    public int a;
    public bool b;
    public string s;
    public object o;
    public static int Main()
    {
        //
생성된 객체 v 의 모든 멤버변수는 자동으로 초기값으로 설정된다.
        DefaultValueTester v = new DefaultValueTester();
        //
지역변수는 사용전에 초기화가 필요하다.
        int localInt;
        Console.WriteLine(localInt);  //
오류 !!!
        return 0;
    }
}

 

 

 

값 형식과 참조 형식

 

모든 숫자 데이타 형식(int, float, 등)과 열거형과 구조체를 포괄하는 값 기반형식은 스택에 할당된다.
따라서 값 형식은 정의된 영역 밖에서는 메모리로부터 곧바로 제거 될 수 있다.
하나의 값 형식을 다른 값 형식에 할당하면, 기본적으로 멤버 대 멤버 복사가 이루어진다.

Code:

using System;
class ValRefClass
{
    public static void Main()
    {
        int i = 99;
        int j = i;
        j = 88;
    }
}
결과
i = 99, j = 88;

 

구조체의 경우도 마찬가지다.

Code:

using System;
struct FOO
{
    public int x, y;
}
class ValRefClass
{
    public static void Main()
    {
        FOO f1 = new FOO();
        f1.x = 100;
        f1.y = 100;
        FOO f2 = f1;
        f2.x = 900;
    }
}
결과
f1.x = 100, f1.y = 100
f2.y = 900, f2.y = 100


이와는 정반대로, 참조 형식(클래스)은 가비지 컬렉션의 대상인 힙에 할당된다.
힙에 할당된 참조 형식은 가비지 컬렉션에 의해 제거되기 전까지는 계속 메모리에 남아 있게 된다.

참조 형식의 대입은 멤버의 복사가 아닌 할당된 인스턴스가 생성된 메모리를 복사하게 된다.
C++
의 포인터 끼리의 대입과 같다고 이해하면 된다.

아래의 예제는 위 구조체 예제에서 구조체 대신 클래스를 사용할 때 참조 형식이 되는 예이다.

Code:

using System;
class FOO
{
    public int x, y;
}
class ValRefClass
{
    public static void Main()
    {
        FOO f1 = new FOO();
        f1.x = 100;
        f1.y = 100;
        FOO f2 = f1;
        f2.x = 900;
    }
}
결과
f1.x = 900, f1.y = 100
f2.y = 900, f2.y = 100

시스템 데이터 형식과 C#별칭

모든 내장 C# 데이터 형식은 사실 System 네임스페이스에 정의되어 있는 시스템 형식에 대한 별칭이다.

Attachment:

system_data.JPG


예를 들면 'int' 는 실제 시스템 형식인 System.Int32 의 약칭 표시가 되는 것이다.

Code:

using System;
class Test
{
    public static void Main()
    {
        System.Int32 a = 1000;  // int a = 1000;
와 같음
        System.Int32 b = 1000;  // int b = 1000;
와 같음
        if (a == b)
            Console.WriteLine("Same value!");
    }
}

 

 

 

 

 

 

값 형식과 참조 형식간의 변환 : 박싱(boxing), 언박싱(Unboxing)

 

C# 에는 값 형식과 참조 형식 간의 변환을 간단하게 할 수 있는 메커니즘이 있는데, 이를 박싱(boxing) 이라고 부른다.


값을 박싱한다는 것은 새로운 객체를 힙에 할당하고 새로 할당된 이 인스턴스에 내부 값을 복사하는 것이다. 이때 반환하는 것은 새로 할당된 객체에 대한 참조자이다.

언박싱의 경우에는 반대의 연산이 일어난다. 언박싱은 객체 참조에 들어 있는 값을 이에 상응하는 값 형식으로 변환해 스택에 올려 놓는 과정을 일컫는 용어이다.
여기서 알맞은 데이터 형식으로 언박스하는 것은 상당히 주의를 요하는 작업이며 형식이 틀리다면 InvalidCastException 예외가 발생한다.

Code:

// 값 데이터 형식을 만든다.
short s1 = 25;
//
값을 객체 참조로 박스한다.
object myObj = s1;
//
참조를 이에 상응하는 short 로 언박스(unboxing) 한다.
short s2 = (short)myObj;
try
{
    //
박스에 포함된 형식이 string 이 아니라 short 이다.
    string str = (string)myObj;
}
catch (InvalidCastException e)
{
    Console.WriteLine("OOPS! {0}", e.ToString());
}

 C# 의 'out' 키워드
다음은 C# 의 'out' 키워드를 이용해서 두정수의 합을 반환하도록 하는 함수이다.
C#
의 'out' 키워드는 호출자가 하나의 메소드 호출을 통해서 여러 개의 반환 값을 얻을 필요가 있을때 매우 유용하다.
C++ 에서 변수의 포인터를 함수의 매개변수로 넘겨서 결과를 받아 오는 것과 유사하다.

Code:

using System;
class MainClass
{
    public static void Add(int x, int y, out int ans)
    {
        ans = x + y;
    }
    public static void Main()
    {
        int x = 9, y = 10, z=0;
        Add(x, y, out z);
    }
}
결과
x=9, y=10, z=19;

C# 의 'ref' 키워드

참조 매개변수는 호출된 메소드에서, 호출자의 범위 안에 선언된 데이터 포인터에 대한 연산을 하고 싶은 경우에 필요하다.
출력 매개변수(out 키워드)는 인자로 넘기기 전에 초기화될 필요가 없다. 하지만 참조 매개변수는 인자로 넘어가기 전에 반드시 초기화 되어야 한다. 왜냐하면 이미 존재하는 형식에 대한 참조자를 전달해야 하기 때문이다.

Code:

using System;
class MainClass
{
    public static void UpperCaseThisString(ref string s)
    {
        //
문자열을 대문자로 변경해서 반환한다.
        s = s.ToUpper();
    }
    public static void Main()
    {
        string s = "Can you really have sonic hearing for $19.00?";
        Console.WriteLine("Before: {0} ", s);
        UpperCaseThisString(ref s);
        Console.WriteLine("After: {0} ", s);
    }
}

out : 출력 매개 변수

1. 변수 초기화 필요치 않음 : 출력용 이기 때문에 함수로 전달되기 전 변수값 할당은 무의미 하다

2. 함수내 반드시 변수에 값 할당 : 출력용 이기 때문에 함수내에서 변수 값이 할당 되어야 함.

 

ref : 참조에 의한 전달

1. 변수 초기화 필요 : 일반 매개변수와 같은 의미

2. 함수내 값 설정하지 않아도 됨

 

 

 

 

 

 

 

 

 

C# 의 'params' 키워드

이 키워드를 이용하면 배열과 같은 다양한 종류의 여러 인수를 하나의 매개변수로서 전달 할 수 있다.

Code:

using System;
class MainClass
{
    public static void DisplayArray(string msg, params int[] list)
    {
        Console.WriteLine(msg);
        for (int i = 0; i < list.Length; i++)
            Console.WriteLine(list[i]);
   [/legend] }
    public static void Main()
    {
        int[] arr = new int[3] { 10, 11, 12 };
        DisplayArray("Here is an array of ints", arr);
    }
}

 

C# 의 구조체

C# 의 구조체도 C++ 형식과 크게 다른것이 없으며, C# 구조체를 별칭으로 하는 동일한 이름의 클래스를 가지지 않는다.
C# 의 클래스와의 차이점은 데이터가 스택에 할당되며 구조체의 대입은 참조가 아닌(주소의 공유가 아닌) 값의 복사가 된다.

클래스와 구조체의 차이점

  • 구조체는 값 형식이다.
  • 모든 구조체 형식은 암시적으로 System.ValueType 에서 상속된다.
  • 구조체 형식의 변수에 대입이 이뤄지면 지정되는 값이 복사된다.
  • 구조체의 기본 값은 모든 값 형식 필드를 각 형식의 기본 값으로 설정하고 모든 참조 필드를 null 로 설정한 것이다.
  • 구조체 형식과 객체 간의 변환에는 박싱과 언박싱 연산이 필요하다.
  • this 의 의미가 다르다.
  • 구조체에 대한 인스턴스 필드 선언은 변수 초기화를 포함할 수 없다.
  • 구조체는 매개변수가 없는 인스턴스 생성자를 선언할 수 없다.
  • 구조체는 소멸자를 선언할 수 없다.

 

 

 

 

 

읽기 전용 속성과 쓰기 전용 속성

앞선 예제에서 EmpID 는 읽기/쓰기 속성으로 만들어졌다. 이것을 읽기 전용으로 구성하려면 set 블록을 빼고 만들면 된다.
마찬가지로 쓰기 전용 속성을 만들고 싶으면 get 블록을 빼면 된다.

읽기 전용 필드 만들기

읽기 전용 속성은 읽기 전용 필드와 밀접하게 관련되어 있다. 읽기 전용 필드는 'readonly' 키워드를 이용해 데이터를 보호한다.
읽기 전용 필드는 생성자에서만 할당 가능하며 이 필드에 값을 할당하려고 하면 컴파일 에러가 발생한다.

Code:

public class Employee
{
    //
읽기 전용 필드 (생성자에서 할당)
    public readonly int empID;
    public Employee(int id)
    {
        //
읽기 전용 필드 할당.
        empID = id;
    }
}

class MainClass
{
    public static void Main()
    {
        Employee p = new Employee(10);
        p.empID = 20;  //
읽기 전용 필드이므로 컴파일 에러.
        Console.WriteLine(p.empID);
    }
};

 

 

 

 

 

 

 

 

 

클래스 멤버 버전 관리

 

C# 에는 메소드 재정의에 대해 논리적으로 정반대에 해당하는 기능인 메소드 숨기기(hiding)가 있다.  .NET *.dll 을 구입해서, 여기에 있는 기본 클래스로부터 새 클래스를 파생시키려 한다고 가정해 보자. 이때 여러분이 만들고자 하는 메소드와 호환되지 않는 같은 이름의 메소드가 기본 클래스에 정의되어 있다면 어떻게 해야 할까?
이런 경우, 바로 객체 사용자가 기본 클래스 구현을 유발하지 않도록 'new' 를 사용하면 된다.

Code:

public class MyBase
{
    public virtual void func()
    {
        Console.WriteLine("Base");
    }
}

public class TestClass : MyBase
{
   
// 이전에 구현된 func() 구현을 모두 감추고 TestClass 고유한 기능을 수행한다.
    public
new void func()
    {
        Console.WriteLine("Child");
    }
}

class MainClass
{
    public static void Main()
    {
        MyBase c1 = new MyBase();
        c1.func();
        c1 = new TestClass();
        c1.func();
        TestClass c2 = new TestClass();
        c2.func();
    }
};


Output

Attachment:

class.JPG

같은 방법으로 파생된 형식의 필드(멤버변수)에도 new 키워드를 적용해서 상속의 연결 관계에서 동일한 이름으로 정의된 데이터 형식을 숨길 수도 있다.

C# 의 종결 프로세스

모든 형식에 C# 스타일의 소멸자를 만들고 싶을 수도 있다. 그러나 그렇게 하면 안된다.
무엇보다도, 종결자의 역할이 .NET 객체가 비관리 리소스를 제거할 수 있게 하는 것이라는 점을 잊어서는 안된다.
종결 메소드의 사용을 지양해야 하는 좀 더 실질적인 이유는 종결에 시간이 소요된다는 것이다.

new
연산자를 이용해서 관리 힙에 객체를 하나 위치시킬 때, 런타임은 자동적으로 이 객체가 사용자 지정 Finalize() 메소드를 지원하는지 검사하게 된다.
만약 지원한다면 이 객체는 종결 가능한 것으로 표시되고, 이 객체에 대한 포인터가 종료 대기열(finalization queue)이라는 이름의 내부 대기열에 저장된다.

가비지 컬렉터가 객체를 메모리로부터 해제할 때라고 판단할 때, 가비지 컬렉터는 종료 대기열 목록에 기재되어 있는 모든 항목을 검사하고, 이 객체를 힙으로 부터 finalization reachable table 이라는 이름의 또다른 CLR 관리 구조로 복사한다.
이때 별도의 스레드가 실행되어 다음 번 가비지 컬렉션시 테이블에 있는 각 객체의 Finalize() 메소드를 호출한다.


임시 소멸 메소드 만들기

살펴본 것과 같이, 객체 종료 프로세스에는 시간이 소요된다. 이상적으로는, 객체를 만들 때 종료 가능한(finalizable) 것으로 표시되지 않도록 디자인하는 것이 좋다. 그러나 비관리 리소스를 조작하는 형식에서는 이 비관리 리소스들을 필요한 때에 그리고 예측이 가능하게 해제할 수 있어야 한다. 이를 위해서 C# 소멸자를 이용할 수도 있지만, 좀 더 나은 방법도 있다.

사용자 정의 임시 메소드를 정의해서 시스템의 모든 객체가 이 메소드를 구현하도록 하는 방법이 있다.
이 메소드 이름을 Dispose() 라고 했다면고 하자. 이때 주의할 점은, 객체 사용자가 해당 형식의 사용을 끝낼 때 객체 참조가 범위 밖으로 벗어나기 전에 Dispose() 를 직접 호출해야 한다는 점이다. 

이 방법을 이용하면, 해당 객체에서 종료 대기열에 접근하거나 가비지 컬렉터가 클래스의 종료 로직을 유발하기를 기다릴 필요 없이 비관리 리소스를 얼마든지 제거할 수 있다.
비관리 리소스가 항상 알맞게 제거될 수 있게 하려면, Dispose() 메소드가 예외를 발생시키지 않고 안전하게 여러 번 호출될 수 있도록 구현해야 한다.


iDisposable
인터페이스

명시적 소멸 루틴을 지원하는 모든 객체들에 일관성을 제공할 수 있도록, .NET 클래스 라이브러리에는 Dispose() 라는 이름의 멤버 하나를 갖는 IDisposable 이라는 이름의 인터페이스가 정의되어 있다. (인터페이스 개념에 대해서는 다른장에서 설명될 것이다.)

Code:

public interface IDisposable
{
    public void Dispose();
}


이 방법을 이용하면, 객체 사용자가 얻어왔던 리소스를 가능한 한 빨리 직접 제거하고, 종료 대기열에 들어가서 발생할 오버헤드를 줄일 수 있게 된다. 호출 로직은 간단하다.

Code:

public class Car : IDisposable
{
    public void Dispose()
    {
        //
내부 비관리 리소스 제거
    }
}

public class MainClass
{
    public static int Main()
    {
        Car c1 = new Car();
        c1.Dispose();
        return 0;
    }
    // c1
은 여전히 힙에 있다가 이 지점에서 컬렉트될 것이다.
}



C#
의 "using" 키워드의 또다른 용도

'using'
키워드는 네임스페이스를 지정하는 용도 이외에 자동으로 Dispose() 메소드를 호출하는 용도로도 사용된다.
IDisposable
인터페이스를 지원하는 객체가 using 블록을 빠져 나갈 때 이 객체의 Dispose() 메소드가 자동적으로 반드시 호출된다.
반면, IDisposable 을 구현하지 않은 형식을 using 블록 안에 지정하면, 컴파일시 에러가 발생한다.

Code:

public void SomeMethod()
{
    using (Car c = new Car())
    {
        //
차를 이용한다.
        // using
블록을 나가면 자동적으로 Dispose() 가 호출된다.
    }
}

 

 

 

 

 

 

가비지 컬렉션 최적화가비지 컬레션시에 관리 힙에 있는 모든 객체를 그대로 하나씩 다 검사해서 제거할 대상을 찾지 않는다. 이렇게 하면, 특히 큰 응용프로그램의 경우, 시간이 상당히 많이 걸리게 된다.

이러한 컬렉션 과정의 최적화를 위해 힙에 있는 각 객체에 '세대'가 할당된다. 힙에 오랫동안 있는 객체일수록 더 오래 머물러 있을 가능성이 있는반면, 최근에 힙에 배치된 객체일수록 응용 프로그램에서 빨리 해제될 가능성이 높다는 것이다.

각 객체는 다음의 세대 중 하나에 속하게 된다. (.NET 1.1 버전에서)


  • 0 세대 : 컬렉션 대상 표시가 된 적이 없는 새로 할당된 객체를 식별한다.
  • 1 세대 : 가비지 컬렉션 검색에서 살아남은 객체를 식별한다. (즉, 제거 대상이지만 힙에 충분히 공간이 있어서 아직 제거되지 않은 것을 말한다.)
  • 2 세대 : 두 번 이상의 가비지 컬렉션에서 살아남은 객체를 식별한다.


컬렉션이 일어나면, GC 가 우선 모든 0세대 객체를 표시하고 제거한다. 이 결과 필요한 만큼의 메모리가 확보되어 있으면, 남아 있는 객체들이 다음에 사용 가능한 세대로 표시된다.

만약 모든 0세대 객체가 힙으로부터 제거되었는데도 여전히 메모리가 부족하면, 1세대 객체가 표시되고 제거된다. 그 다음에도 메모리가 부족하면 2세대로 넘어간다.

이렇게 해서, 새로운 객체는 금방 제거되는 반면 오래된 객체는 계속 사용되는 것으로 간주된다. 
한마디로 말해, GC 는 세대를 토대로 해서 힙영역을 빠르게 해제할 수 있다.


System.GC
형식

System.GC
를 이용하면 가비지 컬렉터와 상호작용할 수 있다.

System.GC
형식 주요 멤버 항목


  • Collect() : GC 가 관리 힙에 있는 모든 객체에 대해서 Finalize() 를 호출하게 한다. 원하면 검색할 세대를 지정할 수 있다.
  • GetGeneration() : 현재 객체가 속한 세대를 반환한다.
  • MaxGeteration : 이 속성은 대상 시스템에서 지원하는 가장 큰 세대를 반환한다.
  • ReRegisterForFinalize() : 객체가 다시 finalizable 하게 되도록 한다. 물론 이전에 SuppressFinalize() 에 의해서 종료되지 않도록 표시되었다는 것을 전제로 한다.
  • SuppressFinalize() : 해당 객체의 Finalize() 메소드가 호출되지 않게 한다.
  • GetTotalMemory() : 현재 힙에 있는 모든 객체들에 의해서 사용되고 있는 메모리와 곧 제거될 객체들의 추산된 합(바이트)을 반환한다. 이 메소드에는 Boolean 매개변수가 있는데, 이 매개변수는 이 메소드 호출시 가비지 컬렉션이 발생할지 아닐지를 지정하는 데 이용한다.



종결될 수 있고(finalizable) 소멸될 수 있는(disposable) 형식 만들기

아래 Car 클래스는 IDisposabe 인터페이스와 C# 스타일의 소멸자를 모두 지원한다.
여기에서는, 엔드 유저가 Dispose() 를 직접 호출하기 때문에, 지정된 객체에 대한 소멸자를 호출할 필요가 없다는 것을 시스템에게 알려주기 위해, Dispose() 메소드가 GC.SuppressFinalize() 를 호출하도록 변경했다.

Code:

public class Car : IDisposable
{
    ~Car()
    {
        //
모든 내부 비관리 리소스를 제거한다.
    }
    public void Dispose()
    {
        //
모든 내부 비관리 리소스를 제거한다.
        ...
        //
사용자가 Dispose() 를 호출하면 finalize할 필요가 없다.
        //
그러므로 finalization 을 억제한다.
        GC.SuppressFinalize(this);
    }
}




가비지 컬렉션 강제하기

관리 힙이 가득 차면 '언제든지' 자동적으로 가비지 컬렉션이 유발되지만, 원한다면, 정적 메소드인 GC.Collect() 를 이용해서 런타임이 가비지 컬렉션을 수행하도록 강제할 수 있다. 그러나 관리 힙의 본래 의도는 프로그래머의 직접적인 제어를 벗어나서 관리되는 것이므로, 가능하면 가비지 컬렉션을 강제로 수행하지 않는 것이 좋다.

Code:

// 가비지 컬렉션을 강제하고, 각 객체가 finalize 되기를 기다린다.
GC.Collect();
GC.WaitForPendingFinalizers()l



세대와 프로그래밍 방식으로 상호작용하기 예제

Code:

using System;

public class Car : IDisposable
{
    private string name;
    public Car(string name)
    {
        this.name = name;
    }
    ~Car()
    {
        Console.WriteLine("In destruct for {0}!", name);
    }
    public void Dispose()
    {
        Console.WriteLine("In Dispose() for {0}!", name);
        GC.SuppressFinalize(this);
    }
}

public class MainClass
{
    public static int Main()
    {
        //
이 차들을 관리 힙에 추가한다.
        Car c1, c2, c3, c4;
        c1 = new Car("Car1");
        c2 = new Car("Car2");
        c3 = new Car("Car3");
        c4 = new Car("Car4");

        //
세대를 표시한다.
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c1));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c2));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c3));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c4));

        //
차 몇대를 직접 제거한다.
        c1.Dispose();
        c3.Dispose();

        // 0
세대를 모두 컬렉트한다.
        GC.Collect(0);

        //
세대를 다시 출력한다.
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c1));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c2));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c3));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c4));

        return 0;
    }
}


Output

Attachment:

dispose.JPG

 

사용자 지정 열거형 만들기 IEnumerable, IEnumerator

사용자 지정 형식인 Car 객체를 모아 놓은 Cars 라는 이름의 클래스를 만들었다고 가정해 보자.
내부의 Car 들을 얻기 위해서는 Cars 를 반복 처리할 때 foreach 구조를 이용하는 것이 편리할 것이다.

Code:

public class Car
{
    private string name;
    public Car(string name)
    { this.name = name; }
    public string CarName 
    { set {name = value; } get { return name; } }
}

public class Cars
{
    private Car[] carArray;
    public Cars()
    {
        carArray = new Car[4];
        carArray[0] = new Car("Car1");
        carArray[1] = new Car("Car2");
        carArray[2] = new Car("Car3");
        carArray[3] = new Car("Car4");
    }
}

public class MainClass
{
    public static void Main(string[] args)
    {
        Cars carLot = new Cars();
        foreach( Car c in carLot )  //
컴파일 오류 !!
        {
            Console.WriteLine("Name: {0} ", c.CarName );
        }
    }
}


그러나 위 코드는, Cars 클래스에 GetEnumerator() 메소드가 구현되지 않았다는 컴파일 에러가 발생할 것이다.
이 메소드는 System.Collections 네임스페이스에 숨어 있는 IEnumerable 인터페이스에 정의되어 있다.

Code:

// foreach 구문을 이용해서 하위 형식을 얻으려면 컨테이너가 반드시 IEnumerable 을 구현해야 한다.
public interface IEnumerable
{
    IEnumerator GetEnumerator();
}


따라서 이 문제를 바로잡기 위해서는 우선 Cars 클래스에 IEnumerable 인터페이스를 추가하고 GetEnumerator() 메소드를 구현해야 한다.
그런데 GetEnumerator() 는 IEnumerator 라는 이름의 또 다른 인터페이스를 반환하게 되어있다.
IEnumerator
는 임의의 객체가 형식들의 내부 컬렉션을 순회하는데 이용할 수 있다.
역시 System.Collections 네임 스페이스에 정의되어 있는 IEnumerator 에는 다음과 같은 세가지 메소드가 정의되어 있다.

Code:

public interface IEnumerator
{
    //
컬렉션의 현재 요소를 가져옵니다.
    object Current { get; }
    //
열거자를 컬렉션의 다음 요소로 이동합니다.
    bool MoveNext();
    //
컬렉션의 첫 번째 요소 앞의 초기 위치에 열거자를 설정합니다.
    void Reset();
}



이제 Cars 클래스는 다음과 같이 수정할 수 있다.

Code:

public class Cars : IEnumerable, IEnumerator
{
    private Car[] carArray;
    int pos = -1;  //
배열의 현재 위치
    public Cars()
    {
        carArray = new Car[4];
        carArray[0] = new Car("Car1");
        carArray[1] = new Car("Car2");
        carArray[2] = new Car("Car3");
        carArray[3] = new Car("Car4");
    }
    // IEnumerator
인터페이스의 메소드 구현
    public bool MoveNext()
    {
        if (pos < carArray.Length - 1)
        {
            pos++;
            return true;
        }
        return false;
    }
    public void Reset() 
    { pos = 0; }
    public object Current 
    { get {return carArray[pos]; } }
    // IEnumerable
인터페이스의 메소드 구현
    public IEnumerator GetEnumerator() 
    { 
         return (IEnumerator)this; 
    }
}


위의 소스코드는 예를 들어 설명하기 위해서 어쩔 수 없이 모두 구현했지만, 이와 같은 IEumerator 인터페이스 구현에는 실제로는 불필요한 부분이 많다. 
배열의 실제 형식인 System.Array 에는 이미 IEnumerator 가 구현되어 있기 대문에, 사실 Car 클래스는 다음과 같이 간략하게 작성될 수 있다.

Code:

public class Cars : IEnumerable // IEnumerator 는 필요하지 않다.
{
    private Car[] carArray;
    public Cars()
    {
        carArray = new Car[4];
        carArray[0] = new Car("Car1");
        carArray[1] = new Car("Car2");
        carArray[2] = new Car("Car3");
        carArray[3] = new Car("Car4");
    }
    // IEnumerable
인터페이스의 메소드 구현
    public IEnumerator GetEnumerator() 
    { 
        //
이제는 내부 배열로 부터 IEnumerator 를 반환한다.
        return carArray.GetEnumerator(); 
    }
}

 

 

복사 가능한 객체 만들기 ICloneable

 

참조 객체의 복사(대입)은 실제 값의 복사가 아닌 단순히 객체의 주소가 복사되는 얕은 복사를 수행한다.
호출자에게 자기 자신의 복사본을 반환할 수 있는 사용자 정의 형식을 만들려면, 표준 ICloneable 인터페이스를 구현하면 된다.

Code:

public interface ICloneable
{
    //
현재 인스턴스의 복사본인 새 개체를 만듭니다.
    object Clone();
}


IConeable
인터페이스를 사용한 예

Code:

public class Point : ICloneable
{
    public int x, y;
    public Point() { }
    public Point(int x, int y) { this.x = x; this.y = y; }
    public override string ToString()
    { return "X: " + x + "Y: " + y; }
    public object Clone()
    { return new Point(this.x, this.y); }
}

public class MainClass
{
    public static void Main()
    {
        Point p1 = new Point(50, 50);
        Point p2 = (Point)p1.Clone();
    }
}


Point
를 위와 같이 구현할 수도 있지만, 좀 더 간단하게 나타낼 수도 있다. Point 형식에 다른 내부 참조 형식에 대한 참조자가 없기 때문에, Clone() 메소드를 다음과 같이 간단하게 할 수도 있다.
( MemberwiseClone()
은 System.Object 에 정의 되어 있는 멤버이다. )

Code:

public object Clone()
{
    // Point
의 각 필드를 멤버 대 멤버 복사.
    return this.MemberwiseClone();
}

 

 

콜벡함수


대부분의 프로그램에서 시스템 내의 객체들은 일반적으로 이벤트, 콜벡 인터페이스와 여타 프로그래밍 구조를 이용해서 '양방향 통신' 에 참여한다.
Windows API
에서는 콜백 함수 또는 줄여서 콜백이라는 이름의 항목을 생성하는 데 C 스타일의 함수 포인터를 이용한다.
프로그래머들은 콜백을 이용해서 하나의 함수가 해당 응용 프로그램에 있는 다른 함수에게 보고(콜벡)하도록 구성할 수 있었다.
포준 C 스타일 함수는 메모리에 있는 주소를 가리키는 것에 지나지 않는다는 데에 문제가 있다.
이상적으로는 콜백에 매개변수의 개수나 형식 그리고 지시된 메소드의 반환 값과 같은 형식 안전 정보가 포함되는 것이 바람직하다.
아쉽게도, 전통적인 콜백 함수에서는 이것이 불가능하기 때문에, 이로 인해 버그나 심각한 충돌 등 여러 런타임 에러가 종종 발생하곤 한다.


델리게이트 Delegate

.NET
에서는 델리게이트를 이용해서 콜벡 기능을 더 안정적이고 더 객체 지향적인 방식으로 수행할 수 있다.
본질적으로, 델리게이트는 해당 응용 프로그램 내에 있는 다른 메소드를 가리키는 객체이다.
.NET Framework
에서는 동기 델리게이트와 비동기 델리게이트를 이용할 수 있다.
구체적으로, 델리게이트에는 세가지 중요한 정보가 포함된다.


  • 델리게이트가 호출하는 메소드의 이름
  • 이 메소드의 인수
  • 이 메소드의 반환 값


*
델리게이트를 설명하는 과정이 다소 복잡해 보이지만, 델리게이트는 함수 포인터를 캡슐화하는 하나의 래퍼 클래스에 지나지 않는다.

 

가장 간단한 델리게이트 예제예제1

주어진 델리게이트의 대상(즉, 호출할 메소드)을 할당하고 싶으면, 해당 메소등의 이름을 델리게이트의 생성자로 전달하면 된다.
이렇게 함으로써, 함수를 직접 호출하는 것처럼 보이는 구문을 이용해서 해당 멤버를 간접적으로 호출할 수 있게 된다.

Code:

using System;
class Program
{
    //
이 메소드는 델리게이트에 의해 호출될 메소드이다.
    public static void PlainPrint(string msg)
    { Console.WriteLine("Msg is : {0} ", msg); }
    //
델리게이트 하나를 정의한다.
    public delegate void AnyMethodTakingAString(string s);
    //
메인함수.
    public static void Main(string[] args)
    {
        //
델리게이트를 만든다.
        AnyMethodTakingAString del;
        del = new AnyMethodTakingAString(PlainPrint);
        //
내부적으로 AnyMethodTakingAString.Invoke() 가 여기에서 호출된다 !!
        del("Hello there...");
        //
델리게이트에 대한 정보를 출력한다.
        Console.WriteLine("I just called : {0} ", del.Method);
    }
}


Output

Attachment:

delegate01.JPG

 

예제 2

델리게이트 객체는 그것이 호출하는 메소드의 실제 이름과는 크게 상관이 없다. 
원한다면 다음과 같이 대상 메소드를 동적으로 변경할 수도 있다.

Code:

using System;
class Program
{
    public static void PlainPrint(string msg)
    { Console.WriteLine("Msg is : {0} ", msg); }
    public static void UpperCasePrint(string msg)
    { Console.WriteLine("Msg is : {0} ", msg.ToUpper()); }


    public delegate void AnyMethodTakingAString(string s);


    public static void Main(string[] args)
    {
        AnyMethodTakingAString del;
        del = new AnyMethodTakingAString(PlainPrint);
        del("Hello there...");
        Console.WriteLine("I just called : {0}\n", del.Method);


        //
델리게이트를 재할당하고 호출한다.
        del = new AnyMethodTakingAString(UpperCasePrint);
        del("Hello there...");
        Console.WriteLine("I just called : {0}\n", del.Method);
    }
}

Output

Attachment:

delegate02.JPG

 

예제3

System.Delegate
기본 클래스에 포함된 호출 리스트에 여러 개의 메소드를 삽입하려면, 오버로드된 += 연산자를 이용하면 된다.

Code:

using System;
class Program
{
    public static void PlainPrint(string msg)
    { 
        Console.WriteLine("Msg is : {0} ", msg); 
    }
    public static void UpperCasePrint(string msg)
    {
        Console.WriteLine("Msg is : {0} ", msg.ToUpper()); 
    }
    public delegate void AnyMethodTakingAString(string s);


    public static void Main(string[] args)
    {
        //
멀티 캐스팅
        AnyMethodTakingAString del;
        del = new AnyMethodTakingAString(PlainPrint);
        del += new AnyMethodTakingAString(UpperCasePrint);
        del("Hello there...");
    }
}


Output

Attachment:

delegate03.JPG

 

 

좀 더 복잡한 델리게이트 예제

현재, 위에서 만든 델리게이트는 논리적으로 관련된 클래스 형식으로부터 분리되어 있다.
이렇게 해도 문제는 없지만, 델리게이트를 클래스 내에서 직접 정의 하는 방법이 좀 더 현명한 방법니다.

Code:

using System;
using System.Collections;

public class Car
{
    private string name;
    private bool isDirty;
    private bool shouldRotate;
    public delegate void CarDelegate(Car c);
    public Car(string name, bool dirty, bool rotate) 
    { 
        this.name = name;
        isDirty = dirty; 
        shouldRotate = rotate; 
    }
    public bool Dirty
    {
        get { return isDirty; }
        set { isDirty = value; }
    }
    public bool Rotate
    {
        get { return shouldRotate; }
        set { shouldRotate = value; }
    }
}

public class Garage
{
    ArrayList theCars = new ArrayList();
    public Garage()
    {
        theCars.Add(new Car("Viper", true, false));
        theCars.Add(new Car("Fred", false, false));
        theCars.Add(new Car("Stan", false, true));
    }
    public void ProcessCar(Car.CarDelegate proc)
    {
        Console.WriteLine("*** Calling: {0} ***", proc.Method.ToString());
        //
인스턴스 메소드를 호출하는가 아니면 정적메소드를 호출하는가 ?
        if (proc.Target != null)
            Console.WriteLine("--> Target: {0}", proc.Target.ToString());
        else
            Console.WriteLine("--> Target is a static method");
        //
메소드를 호출하면서 각 차를 전달한다.
        foreach (Car c in theCars)
            proc(c);
        Console.WriteLine();
    }
}

public class CarApp
{
    //
델리게이트의 대상.
    public static void WashCar(Car c)
    {
        if (c.Dirty)
            Console.WriteLine("Cleaning a car");
        else
            Console.WriteLine("This car is already clean...");
    }
    //
델리게이트의 또다른 대상.
    public static void RotateTires(Car c)
    {
        if (c.Rotate)
            Console.WriteLine("Tires have been rotated");
        else
            Console.WriteLine("Don't need to be rotated...");
    }
    public static int Main(string[] args)
    {
        //
정비 공장을 만든다.
        Garage g = new Garage();
        //
더러운 차를 세차한다.
        g.ProcessCar(new Car.CarDelegate(WashCar));
        //
타이어를 교체한다.
        g.ProcessCar(new Car.CarDelegate(RotateTires));
        return 0;
    }
}

Output

Attachment:

delegate04.JPG

멀티캐스트 델리게이트를 이용하면 여러 델리게이트를 한번에 호출할 수 있다.
멀티캐스트 델리게이트는 여러가지 방법으로 구현할 수 있다.

Code:

public static int Main(string[] args)
{
    //
정비 공장을 만든다.
    Garage g = new Garage();
    //
두 개의 델리게이트를 새로 정의한다.
    Car.CarDelegate wash = new Car.CarDelegate(WashCar);
    Car.CarDelegate rotate = new Car.CarDelegate(RotateTires);
    //
멀티캐스트 델리게이트에 오버로드된 + 연산자를 이용할 수 있다.
    g.ProcessCar(wash + rotate);
    return 0;
}


+
연산자는 정적 Delegate.Combine() 메소드를 호출하는 약어 표시이다.

Code:

// + 연산자는 Combie() 메소드와 동일한 효과를 발휘한다.
g.ProcessCar((Car.CarDelegate)Delegate.Combine(wash + rotate));


이 새 델리게이트를 나중에도 사용하려면 다음과 같이 작성할 수도 있다.

Code:

// 두 개의 델리게이트를 새로 정의한다.
Car.CarDelegate wash = new Car.CarDelegate(WashCar);
Car.CarDelegate rotate = new Car.CarDelegate(RotateTires);
//
이 새로운 델리게이트를 나중에 사용하기 위해서 저장해 둔다.
MulticastDelegate d = wash + rotate;
//
이 새로운 델리게이트를 ProcessCars() 메소드로 보낸다.
g.ProcessCar((Car.CarDelegate)d);


멀티캐스트 델리게이트를 목록에서 항목을 제거하고 싶으면, Remove() 메소드를 호출하면 된다.

Code:

// 이 정적 Remove() 메소드는 Delegate 형식을 반환한다.
Delegate washOnly = MulticastDelegate.Remove(d, rotate);
g.ProcessCars((Car.CarDelegate)washOnly);

 

 

 

 

 

 

 

비동기적 델리게이트

델리게이트 함수 호출을 멀티스레딩으로 메인 스레드와 별도의 스레드에서 실행되게 할 수도 있다.
C#
컴파일러가 'delegate' 키워드를 처리할 때, BeginInvoke() 와 EndInvoke() 라는 이름의 두 메소드가 동적으로 생성되는데 비동기적으로 호출할때 사용된다.

동기 델리게이트의 호출

Code:

using System;
using System.Threading;

public class CarApp
{
    public static void MyPrint(string msg)
    {
        Console.WriteLine("MyPrint() is on thread {0}", Thread.CurrentThread.GetHashCode());
        Thread.Sleep(10000);
        Console.WriteLine("msg : {0}", msg);
    }    
    public delegate void NewDelegate(string msg);
    public static int Main(string[] args)
    {
        Console.WriteLine("Main() is on thread {0}", Thread.CurrentThread.GetHashCode());
        NewDelegate d = new NewDelegate(MyPrint);
        d("Your function is ready !");
        Console.WriteLine("Done invoking delegate");
        return 0;
    }
}


Output

Attachment:

delegate05.JPG

 

 

 

 

메소드를 비동기적으로 호출하기.

Code:

using System;
using System.Threading;

public class CarApp
{
    public static void MyPrint(string msg)
    {
        Console.WriteLine("MyPrint() is on thread {0}", Thread.CurrentThread.GetHashCode());
        Thread.Sleep(10000);
        Console.WriteLine("msg : {0}", msg);
    }    
    public delegate void NewDelegate(string msg);
    public static int Main(string[] args)
    {
        Console.WriteLine("Main() is on thread {0}", Thread.CurrentThread.GetHashCode());
        NewDelegate d = new NewDelegate(MyPrint);
        IAsyncResult itfAR = d.BeginInvoke("Your function is ready !", null, null);
        Console.WriteLine("Done invoking delegate");
        //
다른 작업을 한다...
        d.EndInvoke(itfAR);
        return 0;
    }
}


Output

Attachment:

delegate06.JPG

 

 

 

 

 

 

비동기적 델리게이트로서의 콜벡

Code:

using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

public class CarApp
{
    //
델리게이트 함수 호출이 완료되었을때 호출될 함수.
    public static void MyCallBack(IAsyncResult itfAR)
    {
        Console.WriteLine("DelegateCallBack on thread {0}", Thread.CurrentThread.GetHashCode());
        AsyncResult res = (AsyncResult)itfAR;
        NewDelegate d = (NewDelegate)res.AsyncDelegate;
        d.EndInvoke(itfAR);
    }
    public static void MyPrint(string msg)
    {
        Console.WriteLine("MyPrint() is on thread {0}", Thread.CurrentThread.GetHashCode());
        Thread.Sleep(10000);
        Console.WriteLine("msg : {0}", msg);
    }    
    public delegate void NewDelegate(string msg);
    public static int Main(string[] args)
    {
        Console.WriteLine("Main() is on thread {0}", Thread.CurrentThread.GetHashCode());
        NewDelegate d = new NewDelegate(MyPrint);
        d.BeginInvoke("Your function is ready !", new AsyncCallback(MyCallBack), null);
        Console.WriteLine("Done invoking delegate");
        Console.ReadLine(); //
호출을 마칠때까지 콘솔이 떠 있게 하기 위해.
        return 0;
    }
}


Output

Attachment:

delegate07.JPG

 

 

C# 의 동기화동기화를 하지 않은 소스 예제

Code:

using System;
using System.Threading;

internal class WorkerClass
{
    private int theInt;
    public void DoSomeWork()
    {
        theInt++;
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("theInt: {0}, i: {1}, current thread: {2}",
                theInt, i, Thread.CurrentThread.Name);
            Thread.Sleep(1000);
        }
    }
}

public class App
{
    public static void Main()
    {
        //
단일 작업 객체를 만든다.
        WorkerClass w = new WorkerClass();
        //
세개의 부 스레드를 만들어 각 스레드가 동일한 공유객체를 호출하게 만든다.
        Thread threadA = new Thread(new ThreadStart(w.DoSomeWork));
        threadA.Name = "A";
        Thread threadB = new Thread(new ThreadStart(w.DoSomeWork));
        threadB.Name = "B";
        Thread threadC = new Thread(new ThreadStart(w.DoSomeWork));
        threadC.Name = "C";
        //
하나씩 시작시킨다.
        threadA.Start();
        threadB.Start();
        threadC.Start();
    }
}


Output

Attachment:

thread03.JPG




lock
키워드를 이용한 동기화

'lock'
키워드를 이용하면 코드 블록을 잠가서 현재 스레드가 작업을 완전히 끝낼 때까지 다른 스레드들이 기다리게 만들 수 있다.
'lock'
키워드를 이용하려면 lock 수행문의 범위로 진입하기 위해 스레드가 얻어야 하는 토큰(객체 참조자)을 전달해야 한다.
인스턴스 레벨 메소드를 잠그려면, 현재 형식에 대한 참조자를 전달하기만 하면 된다.

Code:

internal class WorkerClass
{
    private int theInt;
    public void DoSomeWork()
    {
        lock (this)
        {
            theInt++;
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("theInt: {0}, i: {1}, current thread: {2}",
                    theInt, i, Thread.CurrentThread.Name);
                Thread.Sleep(1000);
            }
        }
    }
}


Output

Attachment:

thread04.JPG

 

System.Threading.Monitor 형식을 이용한 동기화

C#
의 lock 수행문은 System.Threading.Monitor 클래스 형식을 이용한 작업을 간소화한 것이다.
Monitor
형식을 이용하면 실행 스레드가 일정 시간 동안 기다리게 하거나(Wait() 메소드를 통해서), 현재 스레드가 완료되었을 때 기다리고 있는 스레드들에게 알려주도록할 수 있다.
내부적으로, 앞의 잠금 로직은 실제로 다음과 같이 처리된다.

Code:

internal class WorkerClass
{
    private int theInt;
    public void DoSomeWork()
    {
        //
모니터에 토큰과 함께 진입한다.
        Monitor.Enter(this);
        try
        {
            theInt++;
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("theInt: {0}, i: {1}, current thread: {2}",
                    theInt, i, Thread.CurrentThread.Name);
                Thread.Sleep(1000);
            }
        }
        finally
        {
            //
모니터를 나가서 토큰을 해제해야 한다.
            Monitor.Exit(this);
        }
    }
}



 

 

 


System.Threading.Interlocked
형식을 이용한 동기화

System.Threading
네임스페이스는 단일 데이터 포인트에서 원자적으로 연산하는 데 이용할 수 있는 형식을 제공한다.

Interlocked 형식의 멤버

  • Increment() : 값을 1만큼 안전하게 증가시킨다.
  • Decrement() : 값을 1만큼 안전하게 감소시킨다.
  • Exchange() : 두 값을 안전하게 교환한다.
  • CompareExchange() : 두 값이 같은지 안전하게 검사하고, 같으면 하나의 값을 세 번째 값으로 바꾼다.


원자적으로 단일 값을 변경하는 과정은 다중 스레드 환경에서 매우 일반적이다. 따라서 동기화 코드를 lock 을 이용해서 작성하기 보다는 Interlocked 형식을 사용하여 작성하는 것이 좋다.

Code:

int i=0;
lock(this)
{ i++; }

 

Code:

// 변경하고자 하는 값을 참조로 전달한다.
int i=0;
Interlocked.Increment(ref i);

 

Code:

int i=9;
Interlocked.Exchange(ref i, 83);

 

Code:

// i의 값이 현재 83 이면, i를 99로 바꾼다.
Interlocked.CompareExchange(ref i, 83, 99);

 

 

 

 

 

 

 

 

Timer Callback 을 이용한 프로그래밍

 

응용 프로그램에서 일정한 간격을 두고 특정 메소드를 호출해야 하는 경우가 종종 있다. 예를 들어, 도우미 함수를 통해 현재 시간을 상태 바에 표시하는 응용 프로그램이 있을 수 있다. 도 다른 예로, 이메일 메시지를 확인하는 백그라운드 작업을 수행하기 위해서 수시로 도우미 함수를 호출하는 응용 프로그램을 만들 수도 있을 것이다.
이러한 경우, System.Threading.Timer 형식을 TimerCallback 이라는 이름의 관련 델리게이트와 함께 이용할 수 있다.
델리게이트 대상이 사용할 정보를 보내고 싶으면, 생성자의 두번째 매개변수에 있는 null 값을 적당한 정보로 바꾸면 된다.

 

Code:

using System;
using System.Threading;

public class App
{
    static void PrintTime(object state)
    {
        Console.WriteLine("Time is: {0}", DateTime.Now.ToLongTimeString());
    }

    public static void Main()
    {
        TimerCallback timeCB = new TimerCallback(PrintTime);
        Timer t = new Timer(
            timeCB, // TimerCallback
델리게이트 형식.
            null,   //
호출된 메소드로 전달될 정보 (정보가 없으면 null)
            0,      //
시작하기 전에 기다릴 시간.
            1000);  //
호출 사이의 간격
        Console.WriteLine("Hit key yo terminate...");
        Console.ReadLine();
    }
}

 

 

 

 

 

 

 

 

System.Type 클래스

 

System.Type 클래스에는 현재 관찰 중인 형식에 대한 중요한 정보를 추출해 내는데 이용할 수 있는 여러 가지 메소드들이 포함되어 있다.

System.Type 의 멤버

  • IsAbstract / IsArray / IsClass / IsCOMObject / IsEnum / IsInterface / IsPrimitive / IsNestedPublic / IsNestedPrivate / IsSealed / IsValueType
    :
    이 속성들을 이용하면 참조하고 있는 Type 에 대한 여러 가지 기본적인 정보를 알아낼 수 있다. (즉, 추상 메소드인지, 배열인지, 중첩 클래스인지 등)
  • GetConstructors() / GetEvents() / GetFields() / GetInterfaces() / GetMombers() / GetNestedTypes() / GetProperties() 
    :
    이 메소드들을 이용하면 알아내고 싶은 항목들(인터페이스, 메소드, 속성 등)을 나타내는 배열을 얻을 수 있다. 각 메소드들은 관련된 배열을 반환한다
  • FindMembers() : 검색 기준에 기반해서, MemberInfo 형식의 배열을 반환한다.
  • GetType() : 이 정적 메소드는 해당 문자열 이름에 대한 Type 인스턴스를 반환한다.
  • InvokeMember() : 이 메소드를 이용하면 해당 아이템에서 late 바인딩을 이용할 수 있다.




형식 참조자 얻기

1. System.Object
에 정의된 메소드로서 Type 클래스의 인스턴스를 반환하는 GetType() 이라는 메소드를 이용할 수 있다.

Code:

// 유효한 Foo 인스턴스를 이용해서 Type 을 추출한다.
Foo theFoo = new Foo();
Type t = theFoo.GetType();



2. Type
클래스 자체를 이용해서 정적 멤버인 GetType() 을 호출하고 얻어내고자 하는 항목의 이름을 지정할 수 있다.

Code:

// 정적 메소드인 Type.GetType() 을 이용해서 Type 을 가져온다.
Type t = null;
t = Type.GetType("Foo");
//
별도의 어셈블리에 있는 중첩 형식을 가져온다.
t = Type.GetType("MyNamespace.OuterType+NestedType, myOtherAsm");



3. C#
의 typeof() 연산자를 이용해서 Type 의 인스턴스를 얻을 수도 있다.

Code:

// typeof 를 이용해서 Type 을 가져온다.
Type t = typeof(Foo);



 

 

 


Type
클래스 활용 예제

Code:

using System;
using System.Reflection;

namespace TheType
{
    //
두 개의 인터페이스
    public interface IFaceOne
    { void MethodA(); }
    public interface IFaceTwe
    { void MethodB(); }
    // Foo
는 이 두 인터페이스를 지원한다.
    public class Foo : IFaceOne, IFaceTwe
    {
        //
필드
        public int MyIntField;
        public string myStringField;
        //
메소드
        public void myMethod(int p1, string p2) { }
        //
속성
        public int MyProp
        {
            get { return MyIntField; }
            set { MyIntField = value; }
        }
        //
인터페이스
        public void MethodA() { }
        public void MethodB() { }
    }


    public class App
    {
        public static void Main()
        {
            Foo f = new Foo();
            Type t = f.GetType();
            Console.WriteLine("***** Various stats about Foo *****");
            Console.WriteLine("Full name is: {0}", t.FullName);
            Console.WriteLine("Base is: {0}", t.BaseType);
            Console.WriteLine("Is it abstract? {0}", t.IsAbstract);
            Console.WriteLine("Is it a COM object? {0}", t.IsCOMObject);
            Console.WriteLine("Is it sealed? {0}", t.IsSealed);
            Console.WriteLine("Is it a class? {0}", t.IsClass);
            Console.WriteLine("***** Properties of Foo *****");
            PropertyInfo[] pi = t.GetProperties();
            foreach (PropertyInfo prop in pi)
                Console.WriteLine("Prop: {0}", prop.Name);
            Console.WriteLine("***** Methods of Foo *****");
            MethodInfo[] mi = t.GetMethods();
            foreach (MethodInfo m in mi)
                Console.WriteLine("Method: {0}", m.Name);
            Console.WriteLine("***** Fields of Foo *****");
            FieldInfo[] fi = t.GetFields();
            foreach (FieldInfo field in fi)
                Console.WriteLine("Field: {0}", field.Name);
            Console.WriteLine("***** Interfaces of Foo *****");
            Type[] ifaces = t.GetInterfaces();
            foreach (Type i in ifaces)
                Console.WriteLine("Interface: {0}", i.Name);
            Console.WriteLine("**************************");
        }
    }
}


Output

Attachment:

type01.JPG


 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

MVC4 Could not load type 'System.ServiceModel.Activation.HttpModule'

PROGRAMING/ASP.NET 2014. 11. 25. 13:49

Could not load type 'System.ServiceModel.Activation.HttpModule'


Have you started working on a .NET 4.0 project and received the following error?
Could not load type ‘System.ServiceModel.Activation.HttpModule’ from assembly ‘System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.Exception Details: System.TypeLoadException: Could not load type ‘System.ServiceModel.Activation.HttpModule’ from assembly ‘System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

If you have, you probably have installed .Net framework 4.0 on IIS and then enable either a .Net 3.0 or 3.5 WCF feature.  To fix you need to reconfigure ASP.NET by using the following command depending on the version of ASP.NET you have installed.

IIS 32 bit

%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis /iru

IIS 64 bit

%SYSTEMROOT%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis /iru


출처: http://www.jasonlinham.co.uk/2011/11/could-not-load-type-systemservicemodela.html

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Lecture3 : Deploy Rails App through Haroku

PROGRAMING/Ruby On Rails 2013. 9. 3. 15:08

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Lecture2 : Version control with Git

PROGRAMING/Ruby On Rails 2013. 9. 3. 14:00

Git에 관한 기본을 다음 링크를 참고해서 공부해보세요.

http://paransilverlight.tistory.com/241

 

 

 1. .Gitigrnore 파일을 찾아서 version 관리를 무시하고 싶은 목록을 작성한다.

 

 

 

 

2. git init 명령어를 사용해서 git을 프로젝트에 추가한다.

   git add . 명령어를 사용해서 모든 파일을 local repository에서 추가한다.

 

 

3. git status를 사용해서 chage된 것을 확인할 수 있다.

 

 

 

4. git commit -m "Initial commit" 명령어를 사용해서 Local Repository에 commit 한다.

   SVN과 다르게 아직 서버에서 commit 된 상태가 아닙니다.

 

5. Github 사이트에 접속해서 new repository를 생성한다. https://github.com/new

   (SSH를 등록해야할 필요가 있을 수 있다.)

 

 

 

6.git config 명령어를 사용해서 username과 email address를 local에 생성한 git에 등록

  git remote add origin 명령을 사용해서 Github 사이트에 생성한 저장소와 연결

  git push origin master 명령을 사용해서 Githut Remote Repository에 Local repository의 파일을 push  한다.

 

 

 

 

7. Remote Repository에 파일이 push 된 것을 확인 할 수 있다.

 

 

 

 

 

 

 

 

   

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Lecture1 : My First Rails Application

PROGRAMING/Ruby On Rails 2013. 9. 3. 13:50

1. 프로젝트가 생성되기를 원하는 디렉토리로 이동 후 rails new "Project 이름" 을 입력

    자동으로 프로젝트에 필요한 폴더 및 파일 그리고 Gem이라고 불리는 Package가 생성된다.

 

 

 

 

2. Gemfile을 찾아서 더 필요한 Gem을 추가 후에 Gemfile이 있는 디렉토리로 이동 후

    bundle install을 입력하면  https://rubygems.org에서 필요한 Gem을 다운 받아서 설치한다.

  ( Nuget, Ant와 같이 Package를 관리 하는 듯)

 

 

 

 

 

3. 이제 rails server를 입력하면 Web Servier에서 나의 Rails First App이 localhost:3000에서

   다음과 같이 실행되는 것을 볼 수 있다.

 

 

 

현재까지 진행한 프로젝트 파일

firstApp.zip

 

 

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Tutorial 사이트 및 E-Book

PROGRAMING/Ruby On Rails 2013. 9. 3. 10:05

f루비 초보를 위한 15가지

http://www.looah.com/article/view/1308

 

코드 스쿨 : 루비강좌

http://www.codeschool.com/

 

루비 문법 강좌 + 환경설정

http://quit20.egloos.com/category/Ruby/page/2

 

 

유투브 동영상 강좌 + E_book

http://www.youtube.com/user/RubyOnRailsVideos/videos?sort=da&view=0&flow=grid

 

ruby_on_rails_tutorial_2nd_edition.zip

 

저는 현재 유투브 동영상 강좌와 E-book을 참고해서 공부하고 있습니다.

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,
  • «
  • 1
  • 2
  • 3
  • 4
  • ···
  • 6
  • »

카테고리

  • Inforamtion Technology (281)
    • DESIGN PATTERN (33)
      • 실용주의 디자인패턴 (29)
    • SOFTWARE ENGINEERING (21)
      • Art Of Readable Code (12)
      • Object Oriented Programming (6)
      • TDD (2)
    • FRAMEWORK (22)
      • Spring.net (2)
      • LightSwitch (20)
    • PROGRAMING (58)
      • C# (20)
      • .NET (6)
      • HTML5 (7)
      • ASP.NET (9)
      • SILVERLIGHT (7)
      • Ruby On Rails (6)
    • PROJECT MANAGEMENT (10)
      • SW Version Management (7)
      • Schedulring Management (1)
    • BOOKS (18)
    • MOBILE APP (1)
      • SENCHA TOUCH (1)
    • SECURITY (5)
    • MES (1)
    • B2B (14)
      • WEBMETHODS (4)
    • ERP (53)
      • SAP/R/3 (51)
    • ABOUT TOOLS (2)
    • FUNDAMENT CONCEPT (21)
    • SOA BPM (22)
    • PORTFOLIO (0)

태그목록

  • 동시성
  • 프로그래밍
  • 병렬

최근에 받은 트랙백

글 보관함

링크

파란실버라이트

블로그 이미지

To remember the time when I started learning Silver Light!

LATEST FROM OUR BLOG

RSS 구독하기

LATEST COMMENTS

BLOG VISITORS

  • Total :
  • Today :
  • Yesterday :

Copyright © 2015 Socialdev. All Rights Reserved.

티스토리툴바