반응형


형식 매개 변수에 대한 제약 조건


제약 조건은 형식 인수에서 갖추고 있어야 하는 기능을 컴파일러에 알립니다. 제약 조건이 없으면 형식 인수가 어떤 형식이든 될 수 있습니다. 컴파일러는 모든 .NET 형식의 궁극적인 기본 클래스인 Object의 멤버만 가정할 수 있습니다. 자세한 내용은 제약 조건을 사용하는 이유를 참조하세요. 클라이언트 코드에서 제약 조건에 의해 허용되지 않는 형식을 사용하여 클래스를 인스턴스화하려고 하면 컴파일 시간 오류가 발생합니다. 제약 조건은 where 상황별 키워드를 사용하여 지정됩니다. 다음 표에는 7가지 형식의 제약 조건이 나와 있습니다.

제약 조건설명
where T : struct형식 인수는 값 형식이어야 합니다. Nullable를 제외한 임의의 값 형식을 지정할 수 있습니다. 자세한 내용은 Nullable 형식 사용을 참조하세요.
where T : class형식 인수는 참조 형식이어야 합니다. 이 제약 조건은 모든 클래스, 인터페이스, 대리자 또는 배열 형식에도 적용됩니다.
where T : unmanaged형식 인수는 참조 형식일 수 없으며, 모든 중첩 수준에서 참조 형식 멤버를 포함할 수 없습니다.
where T : new()형식 인수에 매개 변수가 없는 public 생성자가 있어야 합니다. 다른 제약 조건과 함께 사용할 경우 new() 제약 조건을 마지막에 지정해야 합니다.
where T : <기본 클래스 이름>형식 인수가 지정된 기본 클래스이거나 지정된 기본 클래스에서 파생되어야 합니다.
where T : <인터페이스 이름>형식 인수가 지정된 인터페이스이거나 지정된 인터페이스를 구현해야 합니다. 여러 인터페이스 제약 조건을 지정할 수 있습니다. 제약 인터페이스가 제네릭일 수도 있습니다.
where T : UT에 대해 제공되는 형식 인수는 U에 대해 제공되는 인수이거나 이 인수에서 파생되어야 합니다.

일부 제약 조건은 상호 배타적입니다. 모든 값 형식에는 매개 변수가 없는 액세스 가능 생성자가 있어야 합니다. struct 제약 조건은 new() 제약 조건을 의미하고, new() 제약 조건은 struct 제약 조건과 결합할 수 없습니다. unmanaged 제약 조건은 struct 제약 조건을 의미합니다. unmanaged 제약 조건은 struct 또는 new() 제약 조건과 결합할 수 없습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using System;
 
namespace TestProject
{
 
    public interface IIKs
    {
 
    }
 
    public class hy : IIKs
    {
 
        public hy(int s)
        {
 
 
        }
        public hy() => _s = 30;
 
        public override string ToString() => "hy Type !!!!!\t" + _s;
 
        int _s;
    }
 
 
    public class Node<T>
    {
        public Node(T t) => (Next, Data) = (null, t);
 
        public Node<T> Next { get; set; }
 
        T _data;
        public T Data {
            get {
                return _data;
            }
            set {
                _data = value;
            }
        }
    }
 
 
    //T 는 IIKs 를 상속받으면서 기본생성자가 존재해야한다
    public class Car<T> where T : IIKs , new()
    {
        public T ti = new T();
    }
 
 
    class t1s
    {
 
        static void Main(string[] args)
        {
            Car<hy> c = new Car<hy>();
 
            Console.WriteLine(c.ti.ToString());
            
        }
 
    }
}
 

cs


결과 화면
hy Type !!!!!   30

제약 조건을 사용하는 이유

형식 매개 변수 제약을 통해 허용되는 작업 및 메서드 호출 수를 제약 형식 및 해당 상속 계층 구조의 모든 형식에서 지원하는 작업 및 메서드 호출로 늘립니다. 제네릭 클래스 또는 메서드를 디자인할 때 제네릭 멤버에서 단순 할당 이외의 작업을 대해 수행하거나 System.Object에서 지원하지 않는 메서드를 호출하는 경우 형식 매개 변수에 제약 조건을 적용해야 합니다. 예를 들어 기본 클래스 제약 조건은 이 형식의 개체나 이 형식에서 파생된 개체만 형식 인수로 사용된다고 컴파일러에 알립니다. 컴파일러에 이 보장이 있으면 해당 형식의 메서드가 제네릭 클래스에서 호출되도록 허용할 수 있습니다. 다음 코드 예제에서는 기본 클래스 제약 조건을 적용하여 GenericList<T> 클래스(제네릭 소개에 있음)에 추가할 수 있는 기능을 보여 줍니다.

C#
public class Employee
{
    public Employee(string s, int i) => (Name, ID) = (s, i);
    public string Name { get; set; }
    public int ID { get; set; }
}

public class GenericList<T> where T : Employee
{
    private class Node
    {
        public Node(T t) => (Next, Data) = (null, t);        //이 부분은 식 본문 정의글 참고 : http://3dmpengines.tistory.com/2004

        public Node Next { get; set; }
        public T Data { get; set; }
    }

    private Node head;

    public void AddHead(T t)
    {
        Node n = new Node(t) { Next = head };
        head = n;
    }

    public IEnumerator<T> GetEnumerator()
    {
        Node current = head;

        while (current != null)
        {
            yield return current.Data;
            current = current.Next;
        }
    }

    public T FindFirstOccurrence(string s)
    {
        Node current = head;
        T t = null;

        while (current != null)
        {
            //The constraint enables access to the Name property.
            if (current.Data.Name == s)
            {
                t = current.Data;
                break;
            }
            else
            {
                current = current.Next;
            }
        }
        return t;
    }
}

이 제약 조건을 통해 제네릭 클래스에서 Employee.Name 속성을 사용할 수 있습니다. 제약 조건은 T 형식의 모든 항목을 Employee개체 또는 Employee에서 상속하는 개체 중 하나로 보장하도록 지정합니다.

동일한 형식 매개 변수에 여러 개의 제약 조건을 적용할 수 있으며, 제약 조건 자체가 다음과 같이 제네릭 형식일 수 있습니다.

C#
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
    // ...
}

where T : class 제약 조건을 적용하는 경우 == 및 != 연산자는 참조 ID만 테스트하고 값이 같은지 테스트하지 않으므로 형식 매개 변수에 사용하지 않도록 합니다. 이러한 연산자가 인수로 사용되는 형식에서 오버로드되는 경우에도 이 동작이 발생합니다. 다음 코드는 이 내용을 보여 줍니다. String 클래스가 == 연산자를 오버로드하지만 출력이 false입니다.

C#
public static void OpEqualsTest<T>(T s, T t) where T : class
{
    System.Console.WriteLine(s == t);
}
private static void TestStringEquality()
{
    string s1 = "target";
    System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
    string s2 = sb.ToString();
    OpEqualsTest<string>(s1, s2);
}

컴파일러에서 컴파일 시간에 T가 참조 형식이고 모든 참조 형식에 유효한 기본 연산자를 사용해야 한다는 것만 인식합니다. 값 일치 여부를 테스트해야 하는 경우에도 where T : IEquatable<T> 또는 where T : IComparable<T> 제약 조건을 적용하고 제네릭 클래스를 생성하는 데 사용할 모든 클래스에서 인터페이스를 구현하는 것이 좋습니다.

여러 매개 변수 제한

다음 예제와 같이 여러 매개 변수에 제약 조건을 적용하고, 단일 매개 변수에 여러 제약 조건을 적용할 수 있습니다.

C#
class Base { }
class Test<T, U>
    where U : struct
    where T : Base, new()
{ }

바인딩되지 않은 형식 매개 변수

공용 클래스 SampleClass<T>{}의 T와 같이 제약 조건이 없는 형식 매개 변수를 바인딩되지 않은 형식 매개 변수라고 합니다. 바인딩되지 않은 형식 매개 변수에는 다음 규칙이 있습니다.

  • != 및 == 연산자는 구체적인 형식 인수가 이러한 연산자를 지원한다는 보장이 없기 때문에 사용할 수 없습니다.
  • System.Object로/에서 변환하거나 임의의 인터페이스 형식으로 명시적으로 변환할 수 있습니다.
  • null과 비교할 수 있습니다. 바인딩되지 않은 매개 변수를 null과 비교하는 경우 형식 인수가 값 형식이면 비교에서 항상 false를 반환합니다.

제약 조건으로 형식 매개 변수 사용

다음 예제와 같이 고유한 형식 매개 변수가 있는 멤버 함수가 해당 매개 변수를 포함 형식의 형식 매개 변수로 제약해야 하는 경우 제네릭 형식 매개 변수를 제약 조건으로 사용하면 유용합니다.

C#
public class List<T>
{
    public void Add<U>(List<U> items) where U : T {/*...*/}
}

앞의 예제에서 T는 Add 메서드 컨텍스트에서는 형식 제약 조건이고, List 클래스 컨텍스트에서는 바인딩되지 않은 형식 매개 변수입니다.

제네릭 클래스 정의에서 형식 매개 변수를 제약 조건으로 사용할 수도 있습니다. 형식 매개 변수는 다른 형식 매개 변수와 함께 꺾쇠괄호 안에 선언해야 합니다.

C#
//Type parameter V is used as a type constraint.
public class SampleClass<T, U, V> where T : V { }

컴파일러에서 형식 매개 변수가 System.Object에서 파생된다는 점을 제외하고는 형식 매개 변수에 대해 아무 것도 가정할 수 없기 때문에, 제네릭 클래스에서 형식 매개 변수를 제약 조건으로 사용하는 경우는 제한됩니다. 두 형식 매개 변수 사이의 상속 관계를 적용하려는 시나리오에서 제네릭 클래스에 형식 매개 변수를 제약 조건으로 사용합니다.

관리되지 않는 제약 조건

C# 7.3부터 unmanaged 제약 조건을 사용하여 형식 매개 변수가 관리되지 않는 형식이어야 한다고 지정할 수 있습니다. 관리되지 않는 형식은 참조 형식이 아니며, 모든 중첩 수준에서 참조 형식 필드를 포함하지 않는 형식입니다. unmanaged 제약 조건을 사용하면 다음 예제와 같이 메모리 블록으로 조작할 수 있는 형식을 사용하도록 재사용 가능한 루틴을 작성할 수 있습니다.

C#
unsafe public static byte[] ToByteArray<T>(this T argument) where T : unmanaged
{
    var size = sizeof(T);
    var result = new Byte[size];
    Byte* p = (byte*)&argument;
    for (var i = 0; i < size; i++)
        result[i] = *p++;
    return result;
}

앞의 메서드는 기본 제공 형식으로 알려지지 않은 형식에서 sizeof 연산자를 사용하므로 unsafe 컨텍스트에서 컴파일해야 합니다. unmanaged 제약 조건이 없으면 sizeof 연산자를 사용할 수 없습니다.

대리자 제약 조건

C# 7.3부터 System.Delegate 또는 System.MulticastDelegate를 기본 클래스 제약 조건으로 사용할 수도 있습니다. CLR에서는 항상 이 제약 조건을 허용했지만, C# 언어에서는 이 제약 조건을 허용하지 않았습니다. System.Delegate 제약 조건을 사용하면 형식이 안전한 방식으로 대리자에서 작동하는 코드를 작성할 수 있습니다. 다음 코드는 두 대리자가 동일한 형식인 경우 이를 결합하는 확장 메서드를 정의합니다.

C#
public static TDelegate TypeSafeCombine<TDelegate>(this TDelegate source, TDelegate target)
    where TDelegate : System.Delegate
    => Delegate.Combine(source, target) as TDelegate;

위의 메서드를 사용하여 동일한 형식의 대리자를 결합할 수 있습니다.

C#
Action first = () => Console.WriteLine("this");
Action second = () => Console.WriteLine("that");

var combined = first.TypeSafeCombine(second);
combined();

Func<bool> test = () => true;
// Combine signature ensures combined delegates must
// have the same type.
//var badCombined = first.TypeSafeCombine(test);

마지막 줄의 주석 처리를 제거하면 컴파일되지 않습니다. first과 test는 모두 대리자 형식이지만 서로 다른 대리자 형식입니다.

열거형 제약 조건

C# 7.3부터 System.Enum 형식을 기본 클래스 제약 조건으로 지정할 수도 있습니다. CLR에서는 항상 이 제약 조건을 허용했지만, C# 언어에서는 이 제약 조건을 허용하지 않았습니다. System.Enum을 사용하는 제네릭은 System.Enum의 정적 메서드를 사용하여 결과를 캐시하기 위해 형식이 안전한 프로그래밍을 제공합니다. 다음 샘플에서는 열거형 형식에 유효한 값을 모두 찾은 다음, 해당 값을 문자열 표현에 매핑하는 사전을 작성합니다.

C#
public static Dictionary<int, string> EnumNamedValues<T>() where T : System.Enum
{
    var result = new Dictionary<int, string>();
    var values = Enum.GetValues(typeof(T));

    foreach (int item in values)
        result.Add(item, Enum.GetName(typeof(T), item));
    return result;
}

사용된 메서드는 성능에 영향을 주는 리플렉션을 사용합니다. 리플렉션이 필요한 호출을 반복하는 대신, 이 메서드를 호출하여 캐시되고 다시 사용되는 컬렉션을 작성할 수 있습니다.

다음 샘플과 같이 이 메서드는 열거형을 만들고 해당 값과 이름의 사전을 작성하는 데 사용할 수 있습니다.

C#
enum Rainbow
{
    Red,
    Orange,
    Yellow,
    Green,
    Blue,
    Indigo,
    Violet
}
C#
var map = EnumNamedValues<Rainbow>();

foreach (var pair in map)
    Console.WriteLine($"{pair.Key}:\t{pair.Value}");



ref :  https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters


반응형
반응형

=> 연산자


연산자는 C#에서 두 가지 방법으로 사용할 수 있습니다.




이 중에서도 두번째 식 본문의 정의에 대해서 알아보겠습니다




식 본문 정의

식 본문 정의는 간결하고 읽을 수 있는 형식으로 멤버 구현을 제공합니다. 다음과 같은 일반적인 구문을 포함합니다.


member => expression;


여기서 expression은 유효한 식입니다. 은 멤버의 반환 형식이 void이거나 멤버가 생성자 또는 종료자인 경우에만 statement 식일 수 있습니다.

메서드 및 속성 가져오기 문에 대한 식 본문 정의는 C# 6부터 지원됩니다. 생성자, 종료자, 속성 설정 문 및 인덱서에 대한 식 본문 정의는 C# 7부터 지원됩니다.

Person.ToString 메서드에 대한 식 본문 정의는 다음과 같습니다.


public override string ToString() => $"{fname} {lname}".Trim();


다음과 같은 메서드 정의의 약식 버전입니다.

public override string ToString() { return $"{fname} {lname}".Trim(); }



식 본문 멤버




식 본문 정의를 사용하면 간결하고 읽을 수 있는 형식으로 멤버 구현을 제공할 수 있습니다. 메서드 또는 속성과 같은 지원되는 멤버에 대한 논리가 단일 식으로 구성된 경우 식 본문 정의를 사용할 수 있습니다. 식 본문 정의의 일반 구문은 다음과 같습니다.


member => expression;


여기서 expression은 유효한 식입니다.

C# 6에서는 메서드 및 속성 가져오기 접근자에 대해 식 본문 정의 지원이 도입되었으며 C# 7.0에서는 지원이 확장되었습니다. 

다음 표에 나열된 형식 멤버와 함께 식 본문 정의를 사용할 수 있습니다.


멤버지원 버전
메서드C# 6
생성자C# 7.0
종료자C# 7.0
속성 가져오기C# 6
속성 설정C# 7.0
인덱서C# 7.0


메서드

식 본문 메서드는 형식이 메서드의 반환 형식과 일치하는 값을 반환하거나 void를 반환하는 메서드의 경우 일부 작업을 수행하는 단일 식으로 구성됩니다. 예를 들어 ToString 메서드를 재정의하는 형식에는 일반적으로 현재 개체의 문자열 표현을 반환하는 단일 식이 포함되어 있습니다.

다음 예제에ToString 메서드를 식 본문 정의로 재정의하는 Person 클래스를 정의합니다. 또한 이름을 콘솔에 표시하는 DisplayName메서드를 정의합니다. return 키워드는 ToString 식 본문 정의에 사용되지 않습니다.


using System; public class Person { public Person(string firstName, string lastName) { fname = firstName; lname = lastName; } private string fname; private string lname; public override string ToString() => $"{fname} {lname}".Trim(); public void DisplayName() => Console.WriteLine(ToString()); } class Example { static void Main() { Person p = new Person("Mandy", "Dejesus"); Console.WriteLine(p); p.DisplayName(); } }



생성자

생성자에 대한 식 본문 정의는 일반적으로 생성자의 인수를 처리하거나 인스턴스 상태를 초기화하는 단일 할당 식 또는 메서드 호출로 구성됩니다.

다음 예제에서는 생성자에 name이라는 단일 문자열 매개 변수가 있는 Location 클래스를 정의합니다. 식 본문 정의에서 Name 속성에 인수를 할당합니다.

public class Location { private string locationName; public Location(string name) => Name = name; public string Name { get => locationName; set => locationName = value; } }


종료자

종료자에 대한 식 본문 정의에는 일반적으로 관리되지 않는 리소스를 해제하는 문 등의 정리 문이 포함되어 있습니다.

다음 예제에서는 식 본문 정의를 사용하여 종료자가 호출되었음을 나타내는 종료자를 정의합니다.

using System; public class Destroyer { public override string ToString() => GetType().Name; ~Destroyer() => Console.WriteLine($"The {ToString()} destructor is executing."); }


속성 가져오기 문

속성 가져오기 접근자를 직접 구현하려는 경우 단순히 속성 값을 반환하는 단일 식에 대해 식 본문 정의를 사용할 수 있습니다. return 문은 사용되지 않습니다.

다음 예제에서는 Location.Name 속성을 정의합니다. 이 속성의 속성 가져오기 접근자는 해당 속성을 지원하는 private locationName필드의 값을 반환합니다.

public class Location { private string locationName; public Location(string name) => Name = name; public string Name { get => locationName; set => locationName = value; } }

식 본문 정의를 사용하는 읽기 전용 속성은 명시적 set 문 없이 구현할 수 있습니다. 사용되는 구문은 다음과 같습니다.

PropertyName => returnValue;


다음 예제에서는 Location 클래스를 정의합니다. 이 클래스의 읽기 전용 Name 속성은 private locationName 필드의 값을 반환하는 식 본문 정의로 구현됩니다.


public class Location { private string locationName; public Location(string name) => locationName = name; public string Name => locationName; }


속성 설정 문

속성 설정 접근자를 직접 구현하려는 경우 속성을 지원하는 필드에 값을 할당하는 한 줄 식에 대해 식 본문 정의를 사용할 수 있습니다.

다음 예제에서는 Location.Name 속성을 정의합니다. 이 속성의 속성 설정 문은 해당 속성을 지원하는 private locationName 필드에 입력 인수를 할당합니다.

public class Location { private string locationName; public Location(string name) => Name = name; public string Name { get => locationName; set => locationName = value; } }


인덱서

속성과 마찬가지로, get 접근자가 값을 반환하는 단일 문으로 구성되거나 set 접근자가 단순 할당을 수행하는 경우 인덱서의 get 및 set 접근자는 식 본문 정의로 구성됩니다.

다음 예제에서는 다양한 스포츠의 이름이 포함된 내부 String 배열을 포함하는 Sports라는 클래스를 정의합니다. 인덱서의 get 및 set 접근자는 둘 다 식 본문 정의로 구현됩니다.

using System; using System.Collections.Generic; public class Sports { private string[] types = { "Baseball", "Basketball", "Football", "Hockey", "Soccer", "Tennis", "Volleyball" }; public string this[int i] { get => types[i]; set => types[i] = value; } }







ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/operators/lambda-operator

ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members

반응형
반응형




전편 : http://3dmpengines.tistory.com/2001?category=509928


다음 예제에서는 abstract 속성을 정의하는 방법을 보여 줍니다. 추상 속성 선언은 속성 접근자의 구현을 제공하지 않습니다. 클래스가 속성을 지원하도록 선언하지만 접근자 구현은 파생 클래스에서 처리되도록 합니다. 다음 예제에서는 기본 클래스에서 상속된 추상 속성을 구현하는 방법을 보여 줍니다.

이 파일에서는 double 형식의 Area 속성을 포함하는 Shape 클래스를 선언합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// compile with: csc -target:library abstractshape.cs
public abstract class Shape
{
    private string name;
 
    public Shape(string s)
    {
        // calling the set accessor of the Id property.
        Id = s;
    }
 
    public string Id
    {
        get
        {
            return name;
        }
 
        set
        {
            name = value;
        }
    }
 
    // Area is a read-only property - only a get accessor is needed:
     public abstract double Area
    {
        get;
    }
 
    public override string ToString()
    {
        return Id + " Area = " + string.Format("{0:F2}", Area);
    }
}

cs


다음 코드에서는 Shape의 세 가지 서브클래스와 이러한 서브클래스에서 Area 속성을 재정의하여 
고유한 구현을 제공하는 방법을 보여 줍니다.



// compile with: csc -target:library -reference:abstractshape.dll shapes.cs public class Square : Shape { private int side; public Square(int side, string id) : base(id) { this.side = side; } public override double Area { get { // Given the side, return the area of a square: return side * side; } } } public class Circle : Shape { private int radius; public Circle(int radius, string id) : base(id) { this.radius = radius; } public override double Area { get { // Given the radius, return the area of a circle: return radius * radius * System.Math.PI; } } } public class Rectangle : Shape { private int width; private int height; public Rectangle(int width, int height, string id) : base(id) { this.width = width; this.height = height; } public override double Area { get { // Given the width and height, return the area of a rectangle: return width * height; } } }




다음 코드에서는 많은 Shape 파생 개체를 만들고 해당 영역을 출력하는 테스트 프로그램을 보여 줍니다.

// compile with: csc -reference:abstractshape.dll;shapes.dll shapetest.cs class TestClass { static void Main() { Shape[] shapes = { new Square(5, "Square #1"), new Circle(3, "Circle #1"), new Rectangle( 4, 5, "Rectangle #1") }; System.Console.WriteLine("Shapes Collection"); foreach (Shape s in shapes) { System.Console.WriteLine(s); } } }

/* Output: Shapes Collection Square #1 Area = 25.00 Circle #1 Area = 28.27 Rectangle #1 Area = 20.00 */



이 샘플은 개별적으로 컴파일된 파일 3개로 구성되었으며, 결과로 생성된 어셈블리는 다음 컴파일 시 참조됩니다.

  • abstractshape.cs: 추상 Area 속성이 포함된 Shape 클래스입니다.

  • shapes.cs: Shape 클래스의 서브클래스입니다.

  • shapetest.cs: 일부 Shape 파생 개체의 영역을 표시할 테스트 프로그램입니다.

예제를 컴파일하려면 다음 명령을 사용합니다.

csc abstractshape.cs shapes.cs shapetest.cs

그러면 shapetest.exe 실행 파일이 생성됩니다.


ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/how-to-define-abstract-properties

반응형
반응형

abstract 키워드를 사용하면, 불완전하여 파생 클래스에서 구현해야 하는 클래스 및 클래스 멤버를 만들 수 있습니다.

sealed 키워드를 사용하면, 이전에 virtual로 표시되었던 클래스나 특정 클래스 멤버의 상속을 방지할 수 있습니다.


추상 클래스 및 클래스 멤버

클래스 정의 앞에 abstract 키워드를 배치하여 클래스를 추상으로 선언할 수 있습니다. 예:


public abstract class A { // Class members here. }


추상 클래스는 인스턴스화할 수 없습니다. 

추상 클래스의 목적은 여러 파생 클래스에서 공유할 수 있는 기본 클래스의 공통적인 정의를 제공하는 것입니다. 

예를 들어 클래스 라이브러리에서 여러 자체 함수에 매개 변수로 사용되는 추상 클래스를 정의한 다음 해당 라이브러리를 사용하는 프로그래머가 파생 클래스를 만들어 클래스의 고유 구현을 제공하도록 할 수 있습니다.

추상 클래스에서는 추상 메서드도 정의할 수 있습니다. 

메서드의 반환 형식 앞에 abstract 키워드를 추가하면 추상 메서드가 정의됩니다. 예:

public abstract class A { public abstract void DoWork(int i); }

추상 메서드에는 구현이 없으므로 메서드 정의 다음에는 일반적인 메서드 블록 대신 세미콜론이 옵니다. 

추상 클래스의 파생 클래스에서는 모든 추상 메서드를 구현해야 합니다. 

추상 클래스에서 기본 클래스의 가상 메서드를 상속하는 경우 추상 클래스에서는 추상 메서드를 사용하여 가상 메서드를 재정의할 수 있습니다. 예:

// compile with: -target:library public class D { public virtual void DoWork(int i) { // Original implementation. } } public abstract class E : D { public abstract override void DoWork(int i); } public class F : E { public override void DoWork(int i) { // New implementation. } }

virtual 메서드는 abstract로 선언되어도 추상 클래스에서 상속된 모든 클래스에 대해 여전히 가상입니다. 

추상 메서드를 상속하는 클래스에서는 메서드의 원본 구현에 액세스할 수 없습니다. 

앞의 예제에서 F 클래스의 DoWork에서는 D 클래스의 DoWork를 호출할 수 없습니다. 

따라서 추상 클래스는 파생 클래스에서 가상 메서드에 대한 새 메서드 구현을 반드시 제공하도록 제한할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
public class F : E
{
    public override void DoWork(int i)
    {
        // New implementation.
        base.DoWork(i); //error
    }
 
}
 

cs

이렇게 호출 할 경우 "base.DoWork(i); 상태 오류 CS0205 추상 기본 멤버를 호출할 수 없습니다."

 


다른 예

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
 
 //interface 는 구현이나 멤버변수를 넣지 못한다
//interface 에 함수를 추가할 수 있는데 정의와 접근제어자는 빠진 상태로 들어갈 수 있고
//정의는 상속 받는 클래스에서 재정의해야한다
public interface ISO
{
    void show();
    int ret(char s);
 
}
 
public abstract class A : ISO
{
     public A()
    {
 
    }
    public A(int a)
    {
    }
 
    public abstract void left();
    public abstract int ret(char s);
    public abstract void show();
 
    public void right()
    {
 
    }
 
    
}
public class B : A
{
    public B() : this(3)
    {
 
    }
 
    public B(int ss)
    {
        System.Console.WriteLine(ss);
    }
 
    public override void left()
    {
        base.right();
    }
 
    public override int ret(char s)
    {
        throw new System.NotImplementedException();
    }
 
    public override void show()
    {
        throw new System.NotImplementedException();
    }
}
 
 
class MainClass
{
    static void Main()
    {
        B ai = new B();
        ai.left();
    }
}
 
 
 
//결과 
//3
 
 

cs



봉인 클래스 및 클래스 멤버

클래스 정의 앞에 sealed 키워드를 배치하여 클래스를 sealed로 선언할 수 있습니다. 예:


public sealed class D { // Class members here. }




  • 봉인 클래스는 기본 클래스로 사용할 수 없습니다. 

  • 그러므로 추상 클래스가 될 수도 없습니다. 

  • 봉인 클래스는 상속할 수 없습니다.


 봉인 클래스는 기본 클래스로 사용될 수 없으므로 일부 런타임 최적화에서는 봉인 클래스 멤버 호출이 약간 더 빨라집니다.

기본 클래스의 가상 멤버를 재정의하는 파생 클래스의 메서드, 인덱서, 속성 또는
이벤트는 해당 멤버를 봉인으로 선언할 수 있습니다.


이렇게 하면 이후에 파생되는 클래스에서는 해당 멤버가 가상이 아니게 됩니다. 

클래스 멤버 선언에서 override 키워드 앞에 sealed키워드를 배치하면 됩니다. 예:


public class D : C { public sealed override void DoWork() { } }




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// compile with: -target:library
public class D
{
    public virtual void DoWork(int i)
    {
        // Original implementation.
    }
}
 
public abstract class E : D
{
    public sealed override void DoWork(int i)
    {
 
    }
}
 
public class F : E
{
 
    public /* new */  void DoWork(int i)
    {
 
    }
}
 
 
class MainClass
{
    static void Main()
    {
        D di = new D();
        F fi = new F();
        di.DoWork(3);
        fi.DoWork(3);
 
    }
}
 
 
/* 결과
경고    CS0114    'F.DoWork(int)'은(는) 상속된 'E.DoWork(int)' 멤버를 숨깁니다.
현재 멤버가 해당 구현을 재정의하도록 하려면 override 키워드를 추가하세요. 
그렇지 않으면 new 키워드를 추가하세요.
*/

cs




ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members


반응형
반응형



implicit 키워드를 통해 int i = 30;  과 같은 형태를 만들 수 있습니다 

(그렇지만 잘 안쓰입니다 일반적인 new Class 형태를 많이 사용하기 때문에..)


implicit


implicit 키워드는 암시적 사용자 정의 형식 변환 연산자를 선언하는 데 사용됩니다. 변환 시 데이터가 손실되지 않는 경우 이 키워드를 통해 사용자 정의 형식과 다른 형식 간에 암시적 변환을 사용할 수 있습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System;
using System.Collections.Generic;
using System.Text;
 
namespace TestProject
{
    public class Hello
    {
 
        public int ddd = 30;
        public double val;
 
        public Hello(double d) { val = d; }
 
        public Hello(int data = 0)
        {
            ddd = data;
        }

//오버로딩이 가능하다
        public static implicit operator Hello(int data)
        {
            return new Hello(data);
        }
 
        // User-defined conversion from Digit to double
        public static implicit operator double(Hello d)
        {
            return d.val;
        }
        //  User-defined conversion from double to Digit
        public static implicit operator Hello(double d)
        {
            return new Hello(d);
        }
 
    }
 
    class test
    {
        static void Main(string[] args)
        {
 
//이처럼 바로 대입이 가능 =>
//public static implicit operator Hello(int data) 가 호출됨
            Hello ins = 130;
 
 
            Hello dig = new Hello(7.0);
            //This call invokes the implicit "double" operator
            double num = dig;
            //This call invokes the implicit "Digit" operator
            Hello dig2 = 12.0;
            Console.WriteLine("num = {0} dig2 = {1}   , {2}", num, dig2.val, ins.ddd);
            Console.ReadLine();
 
 
        }
    }
}
 

cs



결과 


num = 7 dig2 = 12   , 130





암시적 변환은 불필요한 캐스트를 제거하여 소스 코드 가독성을 향상할 수 있습니다. 


그러나 암시적 변환 시 프로그래머가 명시적으로 형식 간에 캐스팅할 필요가 없으므로 예기치 않은 

결과를 방지하기 위해 주의해야 합니다. 


일반적으로 암시적 변환 연산자는 예외를 throw하지 않고 정보가 손실되지 않으므로 

프로그래머에게 알리지 않고 안전하게 사용할 수 있습니다. 


변환 연산자가 이러한 조건에 맞지 않는 경우 explicit로 표시되어야 합니다. 

자세한 내용은 변환 연산자 사용을 참조하세요.





ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/implicit

반응형
반응형



방법: ToString 메서드 재정의



C#의 모든 클래스 또는 구조체는 Object 클래스를 암시적으로 상속합니다. 

따라서 C#의 모든 개체는 해당 개체의 문자열 표현을 반환하는 ToString 메서드를 가져옵니다. 

예를 들어 int 형식의 모든 변수에는 해당 내용을 문자열로 반환할 수 있도록 하는 ToString 메서드가 있습니다.

int x = 42;
string strx = x.ToString();
Console.WriteLine(strx);
// Output:
// 42

사용자 지정 클래스 또는 구조체를 만들 때 해당 형식에 대한 정보를 클라이언트 코드에 제공하려면

ToString 메서드를 재정의해야 합니다.

클래스 또는 구조체의 ToString 메서드를 재정의하려면

  1. 다음 한정자 및 반환 형식으로 ToString 메서드를 선언합니다.

    public override string ToString(){}  
    
  2. 문자열을 반환하도록 메서드를 구현합니다.

    다음 예제에서는 클래스의 특정 인스턴스와 관련된 데이터뿐 아니라 클래스의 이름을 반환합니다.

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    
        public override string ToString()
        {
            return "Person: " + Name + " " + Age;
        }
    }
    

    다음 코드 예제와 같이 ToString 메서드를 테스트할 수 있습니다.

    Person person = new Person { Name = "John", Age = 12 };
    Console.WriteLine(person);
    // Output:
    // Person: John 12




ToString 메서드와 함께 형식 문자열 및 다른 형식의 사용자 지정 서식을 사용하는 방법에 대한 자세한 내용은 형식 서식 지정을 참조하세요.

중요

이 메서드를 통해 제공할 정보를 결정하는 경우 신뢰할 수 없는 코드에서 클래스 또는 구조체가 사용될지 여부를 고려합니다. 악성 코드에서 악용될 수 있는 정보를 제공하지 않으면 주의해야 합니다.



ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/how-to-override-the-tostring-method


반응형
반응형

new 와 override 차이


new 로 재정이 할 경우 업 케스팅시 부모의 것이 호출되지만 override 키워드로 재정의 하게 되면

자식 클래스의 함수가 호출됩니다


yo~!


다음 예제에서는 다른 컨텍스트의 비슷한 동작을 보여 줍니다. 이 예제에서는 Car라는 기본 클래스 하나와 이 클래스에서 파생된 두 클래스 ConvertibleCar 및 Minivan을 정의합니다. 기본 클래스에는 DescribeCar 메서드가 포함되어 있습니다. 이 메서드는 자동차에 대한 기본 설명을 표시한 다음 ShowDetails를 호출하여 추가 정보를 제공합니다. 세 클래스는 각각 ShowDetails 메서드를 정의합니다. new 한정자는 ConvertibleCar 클래스의 ShowDetails를 정의하는 데 사용됩니다. override 한정자는 Minivan 클래스의 ShowDetails를 정의하는 데 사용됩니다.




TestCars1은 다음 출력을 생성합니다. 특히 예상과 다를 수 있는 car2의 결과를 확인합니다. 개체 형식은 ConvertibleCar이지만 DescribeCar는 ConvertibleCar 클래스에 정의된 ShowDetails 버전에 액세스하지 않습니다. 해당 메서드는 override 한정자가 아니라 new 한정자로 선언되기 때문입니다. 결과적으로 ConvertibleCar 개체는 Car 개체와 동일한 설명을 표시합니다. Minivan 개체인 car3의 결과와 비교합니다. 이 경우 Minivan 클래스에서 선언된 ShowDetails 메서드가 Car 클래스에서 선언된 ShowDetails 메서드를 재정의하고, 표시되는 설명은 미니밴에 대해 설명합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace OverrideAndNew2
{
 
    // Define the base class, Car. The class defines two virtual methods,  
    // DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived  
    // class also defines a ShowDetails method. The example tests which version of  
    // ShowDetails is used, the base class method or the derived class method.  
    class Car
    {
        public virtual void DescribeCar()
        {
            System.Console.WriteLine("Four wheels and an engine.");
            ShowDetails();
        }
 
        public virtual void ShowDetails()
        {
            System.Console.WriteLine("Standard transportation.");
        }
    }
 
    // Define the derived classes.  
 
    // Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails  
    // hides the base class method.  
    class ConvertibleCar : Car
    {
        public new void ShowDetails()
        {
            System.Console.WriteLine("A roof that opens up.");
        }
    }
 
    // Class Minivan uses the override modifier to specify that ShowDetails  
    // extends the base class method.  
    class Minivan : Car
    {
        public override void ShowDetails()
        {
            System.Console.WriteLine("Carries seven people.");
        }
    }
 
    class Program
    {
 
        public static void TestCars1()
        {
            System.Console.WriteLine("\nTestCars1");
            System.Console.WriteLine("----------");
 
            Car car1 = new Car();
            car1.DescribeCar();
            System.Console.WriteLine("----------");
 
            // Notice the output from this test case. The new modifier is  
            // used in the definition of ShowDetails in the ConvertibleCar  
            // class.    
            ConvertibleCar car2 = new ConvertibleCar();
            car2.DescribeCar();
            System.Console.WriteLine("----------");
 
            Minivan car3 = new Minivan();
            car3.DescribeCar();
            System.Console.WriteLine("----------");
        }
 
 
        public static void TestCars2()
        {
            System.Console.WriteLine("\nTestCars2");
            System.Console.WriteLine("----------");
 
            var cars = new List<Car> { new Car(), new ConvertibleCar(), new Minivan() };
 
            foreach (var car in cars)
            {
                car.DescribeCar();
                System.Console.WriteLine("----------");
            }
        }
 
        public static void TestCars3()
        {
            System.Console.WriteLine("\nTestCars3");
            System.Console.WriteLine("----------");
            ConvertibleCar car2 = new ConvertibleCar();
            Minivan car3 = new Minivan();
            car2.ShowDetails();
            car3.ShowDetails();
        } 
 
        public static void TestCars4()
        {
            System.Console.WriteLine("\nTestCars4");
            System.Console.WriteLine("----------");
            Car car2 = new ConvertibleCar();
            Car car3 = new Minivan();
            car2.ShowDetails();
            car3.ShowDetails();
        }
 
        public static void Main(string[] args)
        {
            TestCars1();
 
            TestCars2();
 
            TestCars3();
 
            TestCars4();
        }
 
    }
 
 
 
}
 

cs


결과
TestCars1
----------
Four wheels and an engine.
Standard transportation.
----------
Four wheels and an engine.
Standard transportation.
----------
Four wheels and an engine.
Carries seven people.
----------
TestCars2
----------
Four wheels and an engine.
Standard transportation.
----------
Four wheels and an engine.
Standard transportation.
----------
Four wheels and an engine.
Carries seven people.
----------
TestCars3
----------
A roof that opens up.
Carries seven people.
TestCars4
----------
Standard transportation.
Carries seven people.



ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/knowing-when-to-use-override-and-new-keywords


반응형
반응형

Hashtable 클래스



구문

[SerializableAttribute]
[ComVisibleAttribute(true)]
public class Hashtable : IDictionary, ICollection, IEnumerable, 
	ISerializable, IDeserializationCallback, ICloneable




Hashtable 의 키 값은 숫자도 가능하지만 문자열 및 오브젝트도 동시에 가능합니다
즉 구분이 될 수 있는 것들은 가능하지만, null 은 불가능합니다
또한 해쉬 테이블은 저장되는 순서가 보장되지 않습니다



초기화 하 고 다양 한 기능을 수행 하는 방법을 보여 주는 Hashtable 및 해당 키와 값을 출력 하는 방법입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using System;
using System.Collections;
 
class Example
{
    public static void Main()
    {
        // Create a new hash table.
        //
        Hashtable openWith = new Hashtable();
 
        // Add some elements to the hash table. There are no 
        // duplicate keys, but some of the values are duplicates.
        openWith.Add("txt""notepad.exe");
        openWith.Add("bmp""paint.exe");
        openWith.Add("dib""paint.exe");
        openWith.Add("rtf""wordpad.exe");
 
        // The Add method throws an exception if the new key is 
        // already in the hash table.
        try
        {
            openWith.Add("txt""winword.exe");
        }
        catch
        {
            Console.WriteLine("An element with Key = \"txt\" already exists.");
        }
 
        // The Item property is the default property, so you 
        // can omit its name when accessing elements. 
        Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);
 
        // The default Item property can be used to change the value
        // associated with a key.
        openWith["rtf"= "winword.exe";
        Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);
 
        // If a key does not exist, setting the default Item property
        // for that key adds a new key/value pair.
        openWith["doc"= "winword.exe";
 
        // ContainsKey can be used to test keys before inserting 
        // them.
        if (!openWith.ContainsKey("ht"))
        {
            openWith.Add("ht""hypertrm.exe");
            Console.WriteLine("Value added for key = \"ht\": {0}", openWith["ht"]);
        }
 
        // When you use foreach to enumerate hash table elements,
        // the elements are retrieved as KeyValuePair objects.
        Console.WriteLine();
        foreach (DictionaryEntry de in openWith)
        {
            Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
        }
 
        // To get the values alone, use the Values property.
        ICollection valueColl = openWith.Values;
 
        // The elements of the ValueCollection are strongly typed
        // with the type that was specified for hash table values.
        Console.WriteLine();
        foreach (string s in valueColl)
        {
            Console.WriteLine("Value = {0}", s);
        }
 
        // To get the keys alone, use the Keys property.
        ICollection keyColl = openWith.Keys;
 
        // The elements of the KeyCollection are strongly typed
        // with the type that was specified for hash table keys.
        Console.WriteLine();
        foreach (string s in keyColl)
        {
            Console.WriteLine("Key = {0}", s);
        }
 
        // Use the Remove method to remove a key/value pair.
        Console.WriteLine("\nRemove(\"doc\")");
        openWith.Remove("doc");
 
        if (!openWith.ContainsKey("doc"))
        {
            Console.WriteLine("Key \"doc\" is not found.");
        }
 
        //
        //openWith.Add(0, "wordpad.exe11");
        openWith[0= "wordpad.exe11";
 
        //키 값은 null 이 될 수 없지만 값은 null 이 될 수 있습니다
        //openWith.Add(null, "wordpad.exe11");        //error : 'Key cannot be null.'
        //openWith.Add(0, null);
 
        object t1 = new object();
        object t2 = new object();
        openWith.Add(t1, "sdfsdf");
        openWith.Add(t2, "sdfsdf123");
        Console.WriteLine(openWith[t1]);
        Console.WriteLine(openWith[t2]);
 
        Console.WriteLine(openWith[0]);
 
 
        Console.WriteLine();
        foreach (DictionaryEntry de in openWith)
        {
            Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
        }
 
 
    }
}
 
 
/*
An element with Key = "txt" already exists.
For key = "rtf", value = wordpad.exe.
For key = "rtf", value = winword.exe.
Value added for key = "ht": hypertrm.exe
Key = txt, Value = notepad.exe
Key = doc, Value = winword.exe
Key = ht, Value = hypertrm.exe
Key = bmp, Value = paint.exe
Key = dib, Value = paint.exe
Key = rtf, Value = winword.exe
Value = notepad.exe
Value = winword.exe
Value = hypertrm.exe
Value = paint.exe
Value = paint.exe
Value = winword.exe
Key = txt
Key = doc
Key = ht
Key = bmp
Key = dib
Key = rtf
Remove("doc")
Key "doc" is not found.
sdfsdf
sdfsdf123
wordpad.exe11
Key = System.Object, Value = sdfsdf123
Key = txt, Value = notepad.exe
Key = System.Object, Value = sdfsdf
Key = ht, Value = hypertrm.exe
Key = bmp, Value = paint.exe
Key = dib, Value = paint.exe
Key = rtf, Value = winword.exe
Key = 0, Value = wordpad.exe11
*/

cs



이름설명
System_CAPS_pubmethodHashtable()

비어 있는 새 인스턴스를 초기화는 Hashtable 기본 초기 용량을 사용 하 여 클래스, 로드 비율, 해시 코드 공급자 및 비교자입니다.

System_CAPS_pubmethodHashtable(IDictionary)

새 인스턴스를 초기화는 Hashtable 지정된 된 사전에서 새 요소를 복사 하 여 클래스 Hashtable 개체입니다. 새 Hashtable 개체는 복사 된 요소 수와 동일한 초기 용량을 갖고와 기본 로드 비율, 해시 코드 공급자 및 비교자를 사용 하 여 합니다.

System_CAPS_pubmethodHashtable(IDictionary, IEqualityComparer)

새 인스턴스를 초기화는 Hashtable 지정된 된 사전에서 새 요소를 복사 하 여 클래스 Hashtable 개체입니다. 새 Hashtable 개체는 복사 된 요소 수와 동일한 초기 용량을 갖고와 기본 로드 비율 및 지정 된 사용 하 여 IEqualityComparer 개체입니다.

System_CAPS_pubmethodHashtable(IDictionary, IHashCodeProvider, IComparer)

사용되지 않습니다. 새 인스턴스를 초기화는 Hashtable 지정된 된 사전에서 새 요소를 복사 하 여 클래스 Hashtable 개체입니다. 새 Hashtable 개체는 복사 된 요소 수와 동일한 초기 용량을 갖고와 기본 로드 비율과 지정 된 해시 코드 공급자 및 비교자를 사용 하 여 합니다. 이 API는 더 이상 사용되지 않습니다. 다른 방법에 대 한 참조 Hashtable합니다.

System_CAPS_pubmethodHashtable(IDictionary, Single)

새 인스턴스를 초기화는 Hashtable 지정된 된 사전에서 새 요소를 복사 하 여 클래스 Hashtable 개체입니다. 새 Hashtable 개체는 복사 된 요소 수와 동일한 초기 용량을 갖고 및 지정 된 로드 비율과 기본 해시 코드 공급자 및 비교자를 사용 하 여 합니다.

System_CAPS_pubmethodHashtable(IDictionary, Single, IEqualityComparer)

새 인스턴스를 초기화는 Hashtable 지정된 된 사전에서 새 요소를 복사 하 여 클래스 Hashtable 개체입니다. 새 Hashtable 개체는 복사 된 요소 수와 동일한 초기 용량을 갖고 및 지정 된 로드 비율을 사용 하 고 IEqualityComparer 개체입니다.

System_CAPS_pubmethodHashtable(IDictionary, Single, IHashCodeProvider, IComparer)

사용되지 않습니다. 새 인스턴스를 초기화는 Hashtable 지정된 된 사전에서 새 요소를 복사 하 여 클래스 Hashtable 개체입니다. 새 Hashtable 개체 초기 용량이 복사 된 요소 수와 동일 하 고 지정된 로드 비율, 해시 코드 공급자 및 비교자를 사용 합니다.

System_CAPS_pubmethodHashtable(IEqualityComparer)

비어 있는 새 인스턴스를 초기화는 Hashtable 기본 초기 용량을 사용 하 여 클래스 및 로드 비율과 지정 된 IEqualityComparer 개체입니다.

System_CAPS_pubmethodHashtable(IHashCodeProvider, IComparer)

사용되지 않습니다. 비어 있는 새 인스턴스를 초기화는 Hashtable 기본 초기 용량을 사용 하 여 클래스 및 로드 비율과 지정 된 해시 코드 공급자 및 비교자입니다.

System_CAPS_pubmethodHashtable(Int32)

비어 있는 새 인스턴스를 초기화는 Hashtable 지정된 된 초기 용량을 기본 로드 비율, 해시 코드 공급자 및 비교자를 사용 하 여 클래스입니다.

System_CAPS_pubmethodHashtable(Int32, IEqualityComparer)

비어 있는 새 인스턴스를 초기화는 Hashtable 지정된 된 초기 용량을 사용 하 여 클래스 및 IEqualityComparer, 및 기본 로드 비율입니다.

System_CAPS_pubmethodHashtable(Int32, IHashCodeProvider, IComparer)

사용되지 않습니다. 비어 있는 새 인스턴스를 초기화는 Hashtable 지정된 된 초기 용량, 해시 코드 공급자, 비교자 및 기본 로드 비율을 사용 하 여 클래스입니다.

System_CAPS_pubmethodHashtable(Int32, Single)

비어 있는 새 인스턴스를 초기화는 Hashtable 지정된 된 초기 용량을 사용 하 여 클래스 및 로드 비율과 기본 해시 코드 공급자 및 비교자입니다.

System_CAPS_pubmethodHashtable(Int32, Single, IEqualityComparer)

비어 있는 새 인스턴스를 초기화는 Hashtable 지정 된 초기 용량, 로드 비율을 사용 하 여 클래스 및 IEqualityComparer 개체입니다.

System_CAPS_pubmethodHashtable(Int32, Single, IHashCodeProvider, IComparer)

사용되지 않습니다. 비어 있는 새 인스턴스를 초기화는 Hashtable 지정된 된 초기 용량을 사용 하 여 클래스, 로드 비율, 해시 코드 공급자 및 비교자입니다.

System_CAPS_protmethodHashtable(SerializationInfo, StreamingContext)

비어 있는 새 인스턴스를 초기화는 Hashtable 클래스를 사용 하 여 지정 된 직렬화 가능 SerializationInfo및 StreamingContext 개체입니다.

이름설명
System_CAPS_protpropertycomparer

사용되지 않습니다. 가져오거나는 IComparer 를 사용 하는 Hashtable합니다.

System_CAPS_pubpropertyCount

Hashtable에 포함된 키/값 쌍의 수를 가져옵니다.

System_CAPS_protpropertyEqualityComparer

가져옵니다는 IEqualityComparer 를 사용 하는 Hashtable합니다.

System_CAPS_protpropertyhcp

사용되지 않습니다. 해시 코드를 분배할 수 있는 개체를 가져오거나 설정합니다.

System_CAPS_pubpropertyIsFixedSize

Hashtable의 크기가 고정되어 있는지를 나타내는 값을 가져옵니다.

System_CAPS_pubpropertyIsReadOnly

Hashtable가 읽기 전용인지 여부를 나타내는 값을 가져옵니다.

System_CAPS_pubpropertyIsSynchronized

Hashtable에 대한 액세스가 동기화되어 스레드로부터 안전하게 보호되는지를 나타내는 값을 가져옵니다.

System_CAPS_pubpropertyItem[Object]

지정된 키에 연결된 값을 가져오거나 설정합니다.

System_CAPS_pubpropertyKeys

가져옵니다는 ICollection 키를 포함 하는 Hashtable합니다.

System_CAPS_pubpropertySyncRoot

Hashtable에 대한 액세스를 동기화하는 데 사용할 수 있는 개체를 가져옵니다.

System_CAPS_pubpropertyValues

ICollection의 값이 들어 있는 Hashtable을 가져옵니다.

이름설명
System_CAPS_pubmethodAdd(Object, Object)

지정한 키와 값을 가지는 요소를 Hashtable에 추가합니다.

System_CAPS_pubmethodClear()

Hashtable에서 요소를 모두 제거합니다.

System_CAPS_pubmethodClone()

Hashtable의 부분 복사본을 만듭니다.

System_CAPS_pubmethodContains(Object)

Hashtable에 특정 키가 들어 있는지 여부를 확인합니다.

System_CAPS_pubmethodContainsKey(Object)

Hashtable에 특정 키가 들어 있는지 여부를 확인합니다.

System_CAPS_pubmethodContainsValue(Object)

Hashtable에 특정 값이 들어 있는지 여부를 확인합니다.

System_CAPS_pubmethodCopyTo(Array, Int32)

복사본은 Hashtable 요소를 1 차원 Array 인스턴스의 지정한 인덱스에 있습니다.

System_CAPS_pubmethodEquals(Object)

지정한 개체와 현재 개체가 같은지 여부를 확인합니다.(Object에서 상속됨)

System_CAPS_protmethodFinalize()

가비지 컬렉션이 회수하기 전에 개체가 리소스를 해제하고 다른 정리 작업을 수행할 수 있게 합니다.(Object에서 상속됨)

System_CAPS_pubmethodGetEnumerator()

반환 된 IDictionaryEnumerator 을 반복 하는 Hashtable합니다.

System_CAPS_protmethodGetHash(Object)

지정한 키의 해시 코드를 반환합니다.

System_CAPS_pubmethodGetHashCode()

기본 해시 함수로 작동합니다.(Object에서 상속됨)

System_CAPS_pubmethodGetObjectData(SerializationInfo, StreamingContext)

구현 하는 ISerializable 인터페이스를 serialize 하는 데 필요한 데이터를 반환 된 Hashtable합니다.

System_CAPS_pubmethodGetType()

현재 인스턴스의 Type을 가져옵니다.(Object에서 상속됨)

System_CAPS_protmethodKeyEquals(Object, Object)

특정 비교 Object 에 특정 키로는 Hashtable합니다.

System_CAPS_protmethodMemberwiseClone()

현재 Object의 단순 복사본을 만듭니다.(Object에서 상속됨)

System_CAPS_pubmethodOnDeserialization(Object)

ISerializable 인터페이스를 구현하고, deserialization이 완료되면 deserialization 이벤트를 발생시킵니다.

System_CAPS_pubmethodRemove(Object)

Hashtable에서 지정한 키를 가지는 요소를 제거합니다.

System_CAPS_pubmethodSystem_CAPS_staticSynchronized(Hashtable)

동기화 (스레드로부터 안전한 지) 래퍼를 반환 된 Hashtable합니다.

System_CAPS_pubmethodToString()

현재 개체를 나타내는 문자열을 반환합니다.(Object에서 상속됨)

이름설명
System_CAPS_pubinterfaceSystem_CAPS_privmethodIEnumerable.GetEnumerator()

컬렉션을 반복하는 열거자를 반환합니다.

이름설명
System_CAPS_pubmethodAsParallel()

오버로드되었습니다. 쿼리를 병렬화할 수 있도록 합니다.(ParallelEnumerable에서 정의됨)

System_CAPS_pubmethodAsQueryable()

오버로드되었습니다. 변환 된 IEnumerable 에 IQueryable합니다.(Queryable에서 정의됨)

System_CAPS_pubmethodCast<TResult>()

요소에 캐스트는 IEnumerable 지정 된 형식입니다.(Enumerable에서 정의됨)

System_CAPS_pubmethodOfType<TResult>()

요소를 필터링 한 IEnumerable 지정된 된 형식에 기반 합니다.(Enumerable에서 정의됨)


ref : https://msdn.microsoft.com/ko-kr/library/system.collections.hashtable(v=vs.110).aspx




반응형
반응형



CLR 은 VS 에서 컴파일된 중간 언어(IL = MSIL) 을 다시한번 재 컴파일해 각 플랫폼에서 실행 될 수 있는 네이티브 어셈블리로 변환하고 실행하는 역할을 합니다, 여러 플랫폼에서 실행 될 수 있게 하기위한 전략인 것이죠(닷넷 프레임 워크가 존재하는 이유중 하나라고 할 수 있습니다)

CLR 은 닷넷 프레임 워크 안에 존재하며 이것을 프로그래머가 수정하거나 가져다 쓸 수는 없습니다



.NET Framework 플랫폼 아키텍처

C# 프로그램은 CLR(공용 언어 런타임)이라고 하는 가상 실행 시스템과 통합된 클래스 라이브러리 집합을 포함하는 Windows의 통합 구성 요소인 .NET Framework에서 실행됩니다. CLR은 언어 및 라이브러리가 원활하게 함께 작동하는 실행 및 개발 환경을 만들기 위한 기준이 되는 국제 표준인 CLI(공용 언어 인프라)를 Microsoft에서 상업적으로 구현한 것입니다.

C#으로 작성된 소스 코드는 CLI 사양을 준수하는 IL(중간 언어)로 컴파일됩니다. IL 코드 및 리소스(예: 비트맵 및 문자열)는 일반적으로 확장명이 .exe 또는 .dll인 어셈블리라는 실행 파일로 디스크에 저장됩니다. 어셈블리는 어셈블리의 형식, 버전, 문화권 및 보안 요구 사항에 대한 정보를 제공하는 매니페스트를 포함합니다.

C# 프로그램이 실행될 경우 어셈블리가 CLR에 로드되어 매니페스트의 정보를 기준으로 다양한 작업을 수행할 수 있습니다. 그런 다음 보안 요구 사항을 충족되면 CLR은 JIT(Just-In-Time) 컴파일을 수행하여 IL 코드를 네이티브 기계어 명령으로 변환합니다. 

또한 CLR은 자동 가비지 수집, 예외 처리 및 리소스 관리와 관련된 다른 서비스도 제공합니다. 

CLR에서 실행되는 코드는 "관리 코드"라고도 합니다. 

즉, 특정 시스템을 대상으로 하는 네이티브 기계어로 컴파일되는 "비관리 코드"와는 반대됩니다. 다음 다이어그램은 C# 소스 코드 파일, .NET Framework 클래스 라이브러리, 어셈블리 및 CLR의 컴파일 타임 및 런타임 관계를 보여 줍니다.


CLR 로 넘어 가는 것은 MSIL 이며 CLR 안의 JIT 컴파일러를 통해 네이트브 기계어 코드로 변환 됩니다


언어 상호 운용성은 .NET Framework의 주요 기능입니다. 

C# 컴파일러에서 생성된 IL 코드는 CTS(공용 형식 사양=표준 타입 규칙)을 준수하므로 

C#에서 생성된 IL 코드는 .NET 버전의 Visual Basic, Visual C++ 또는 20개 이상의 다른 CTS 규격(닷넷 호환 언어가 지켜야할 타입의 표준 규칙) 언어에서 생성된 코드와 상호 작용할 수 있습니다. 

단일 어셈블리는 다른 .NET 언어로 작성된 여러 모듈을 포함할 수 있고 형식은 마치 같은 언어로 작성된 것처럼 서로를 참조할 수 있습니다.

.NET Framework에는 런타임 서비스 외에, 파일 입/출력부터 문자열 조작, XML 구문 분석, Windows Forms 컨트롤에 이르는 모든 항목에 대해 다양하고 유용한 기능을 제공하는 네임스페이스로 구성된 4,000개 이상의 광범위한 클래스 라이브러리도 포함됩니다. 일반적인 C# 응용 프로그램은 .NET Framework 클래스 라이브러리를 광범위하게 사용하여 일반적인 "배관" 작업을 처리합니다.


ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/getting-started/introduction-to-the-csharp-language-and-the-net-framework

반응형
반응형

인덱서


인덱서는 프로퍼티( get{} set{} )를 확장한 형태와 유사합니다(거의 동일 this[..] 만 빼면)


인덱서는 배열 인덱싱 처럼 원소를 가져오거나 담을 수 있다는 뜻입니다


주로 멤버 배열 변수를 캡슐화 하기 위해 사용됩니다







인덱서는 클라이언트 응용 프로그램에서 배열과 마찬가지 방식으로 액세스할 수 있는 클래스구조체 또는 인터페이스를 만들 수 있게 해 주는 편리한 구문입니다. 인덱서는 주로 내부 컬렉션 또는 배열을 캡슐화하기 위한 형식에서 가장 많이 구현됩니다. 예를 들어 24시간 동안 10번 기록되는 온도를 화씨로 나타내는 TempRecord라는 클래스가 있다고 가정합니다. 클래스에는 온도를 나타내는 float 형식의 "temps"라는 배열과 온도를 기록한 날짜를 나타내는 DateTime이 들어 있습니다. 이 경우 인덱서를 구현하면 클라이언트는 float temp = tr.temps[4] 대신 float temp = tr[4]로 TempRecord 인스턴스의 온도에 액세스할 수 있습니다. 인덱서 표기법은 클라이언트 응용 프로그램의 구문을 단순하게 할 뿐 아니라 클래스와 해당 클래스의 용도를 다른 개발자가 쉽게 이해할 수 있도록 합니다.

클래스나 구조체에 대한 인덱서를 선언하려면 다음 예제에서와 같이 this 키워드를 사용합니다.

public int this[int index]    // Indexer declaration
{
    // get and set accessors
}




인덱서 형식과 해당 매개 변수 형식에는 적어도 인덱서 자체와 동등한 수준으로 액세스할 수 있어야 합니다. 액세스 가능성 수준에 대한 자세한 내용은 액세스 한정자를 참조하십시오.


인덱서 시그니처는 인덱서 정식 매개 변수의 수 및 형식으로 구성됩니다. 이 시그니처는 인덱서 형식 또는 정식 매개 변수 이름을 포함하지 않습니다. 같은 클래스에 두 개 이상의 인덱서를 선언한 경우, 모든 인덱서가 다른 시그니처를 가져야 합니다.

인덱서 값은 변수로 분류되지 않기 때문에 인덱서 값을 ref 또는 out 매개 변수로 전달할 수 없습니다.


예를 들어 다음과 같은 코드는 불가능 합니다

1
public float this[ref int index]
cs


위 코드는 다음과같은 에러를 발생시킵니다

오류 CS0631 이 컨텍스트에서는 ref 및 out을 사용할 수 없습니다.




다른 언어에서 사용할 수 있는 이름을 인덱서에 부여하려면 선언에 name 특성을 사용합니다. 예를 들면 다음과 같습니다.

[System.Runtime.CompilerServices.IndexerName("TheItem")]
public int this [int index]   // Indexer declaration
{
}

이 인덱서의 이름은 TheItem입니다. name 특성을 제공하지 않으면 기본 이름으로 Item이 사용됩니다.




인덱서 형식과 해당 매개 변수 형식에는 적어도 인덱서 자체와 동등한 수준으로 액세스할 수 있어야 합니다. 액세스 가능성 수준에 대한 자세한 내용은 액세스 한정자를 참조하십시오.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class TempRecord
{
    // Array of temperature values 
    private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F,
                                            61.3F, 65.9F, 62.1F, 59.2F, 57.5F };
 
    // To enable client code to validate input  
    // when accessing your indexer. 
    public int Length
    {
        get { return temps.Length; }
    }
    // Indexer declaration. 
    // If index is out of range, the temps array will throw the exception. 
    public float this[int index]
    {
        get
        {
            return temps[index];
        }
 
        set
        {
            temps[index] = value;
        }
    }
}
 
class MainClass
{
    static void Main()
    {
        TempRecord tempRecord = new TempRecord();
        // Use the indexer's set accessor
        tempRecord[3= 58.3F;
        tempRecord[5= 60.1F;
 
 
        // Use the indexer's get accessor 
        for (int i = 0; i < 10; i++)
        {
            System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
        }
 
    }
}
/* Output:
        Element #0 = 56.2
        Element #1 = 56.7
        Element #2 = 56.5
        Element #3 = 58.3
        Element #4 = 58.8
        Element #5 = 60.1
        Element #6 = 65.9
        Element #7 = 62.1
        Element #8 = 59.2
        Element #9 = 57.5
    */
 

cs



C#에서는 인덱스 형식이 정수로만 제한되지 않습니다. 

예를 들어, 인덱서와 함께 문자열을 사용하는 것이 유용할 수 있습니다. 

이러한 인덱서는 컬렉션에서 문자열을 검색하고 적절한 값을 반환하여 구현할 수 있습니다. 

접근자로 오버로드할 수 있으므로 문자열과 정수 버전의 인덱스 형식은 함께 사용될 수 있습니다.




string 형태의 인덱서



이 예제에서는 요일을 저장하는 클래스를 선언합니다. 문자열과 요일 이름을 가져오고 상응하는 정수를 반환하는 get 접근자를 선언합니다. 

예를 들어, 일요일은 0을 반환하고 월요일은 1을 반환하는 방식입니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Using a string as an indexer value 
class DayCollection
{
    string[] days = { "Sun""Mon""Tues""Wed""Thurs""Fri""Sat" };
 
    // This method finds the day or returns -1 
    private int GetDay(string testDay)
    {
  //보다 효율적인 방법은 아니지만 예제를 위해서..
        for (int j = 0; j < days.Length; j++)
        {
            if (days[j] == testDay)
            {
                return j;
            }
        }
 // \" " 를 표현하기 위한 역슬래쉬
        throw new System.ArgumentOutOfRangeException(testDay, "testDay must be in the form \"Sun\", \"Mon\", etc");
    }
 
    // The get accessor returns an integer for a given string 
    public int this[string day]
    {
        get
        {
            return (GetDay(day));
        }
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        DayCollection week = new DayCollection();
        System.Console.WriteLine(week["Fri"]);
 
        // Raises ArgumentOutOfRangeException
        System.Console.WriteLine(week["Made-up Day"]);
 
        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}
// Output: 5

cs







인터페이스 인덱서


interface(C# 참조) 에서 인덱서를 선언할 수 있습니다. 인터페이스 인덱서의 접근자와 클래스 인덱서의 접근자는 다음과 같은 차이점이 있습니다.

  • 인터페이스 접근자는 한정자를 사용하지 않습니다.

  • 인터페이스 접근자에는 본문이 없습니다.

따라서 접근자의 목적은 인덱서가 읽기/쓰기, 읽기 전용 또는 쓰기 전용인지 여부를 나타내는 것입니다.

다음은 인터페이스 인덱서 접근자의 예제입니다.


public interface ISomeInterface
{
    //... 

    // Indexer declaration: 
    string this[int index]
    {
        get;
        set;
    }
}




인터페이스 인덱서 구현 예


다음 예제는 인터페이스 인덱서의 구현 방법을 보여 줍니다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// Indexer on an interface: 
    public interface ISomeInterface
    {
        // Indexer declaration: 
        int this[int index]
        {
            get;
            set;
        }
    }
 
    // Implementing the interface. 
    class IndexerClass : ISomeInterface
    {
        private int[] arr = new int[100];
        public int this[int index]   // indexer declaration
        {
            get
            {
                // 배열 범위 밖의 index 가 올 경우 크래쉬
                return arr[index];
            }
            set
            {
                arr[index] = value;
            }
        }
    }
 
    class MainClass
    {
        static void Main()
        {
            IndexerClass test = new IndexerClass();
            System.Random rand = new System.Random();
            // Call the indexer to initialize its elements. 
            for (int i = 0; i < 10; i++)
            {
                test[i] = rand.Next(); //랜던값 얻기
            }
            for (int i = 0; i < 10; i++)
            {
                System.Console.WriteLine("Element #{0} = {1}", i, test[i]);
            }
 
        }
    }
    /* Sample output:
        Element #0 = 360877544
        Element #1 = 327058047
        Element #2 = 1913480832
        Element #3 = 1519039937
        Element #4 = 601472233
        Element #5 = 323352310
        Element #6 = 1422639981
        Element #7 = 1797892494
        Element #8 = 875761049
        Element #9 = 393083859
     */

cs









ref : https://msdn.microsoft.com/ko-kr/library/2549tw02(v=vs.120).aspx

ref : https://msdn.microsoft.com/ko-kr/library/tkyhsw31(v=vs.120).aspx




반응형
반응형


named parameter


기초 문법이긴 한데 C++ 프로그래머에게는 낯설 수 있는 구문인 named parameter


별건 없고, 단지 좀 더 편의를 제공해 주는 기능 정도입니다


인자 값을넘겨 줄 때 변수명:값 형태로 넘겨 줄 수 있고 순서를 바꿔도 name 지정이기 때문에


넘어가는 것은 이름에 매칭되어 넘어갑니다



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
 
namespace Test
{
    public class Program
    {
 
        public void call(int first, int second)
        {
            Console.WriteLine(first+second);
        }
 
 
        static void Main()
        {
            int dd = 30;
            Program pi = new Program();
            pi.call(second: dd, first: 20);               //50
            pi.call(first: 20, second:2);                 //22
 
        }
 
    }
}
 







optional parameter 


는 C++ 에서 함수의 매개변수에 기본 값을 넣는 것과 동일하다고 생각하면 됩니다


가장 뒤의 매개변수 부터 채워져야 한다는 규칙을 갖고 있습니다





optional parameter 의 경우 오버로딩 함수들 중에서 어떤 함수로 호출될지를 변수 이름으로 지정할 수도 있습니다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;
 
namespace Test
{
    public class Program
    {
 
        public void call(int third)
        {
            Console.WriteLine(third);
        }
 
 
        public void call(int first, int second=30)
        {
            Console.WriteLine(first+second);
        }
 
        static void Main()
        {
            int dd = 30;
            Program pi = new Program();
            pi.call(second: dd, first: 20);                //50
            pi.call(first: 20, second:30);                 //22
 
 
            pi.call(30);            //public void call(int third) 이 호출 됨
 
            pi.call(first:30);      //public void call(int first, int second=30) 이 호출됨
 
            pi.call(third: 30);     //public void call(int third)   이 호출됨
 
        }
    }
}
 

cs




위 처럼 변수명:값 으로 오버로딩 함수중 하나를 택할 수 있지만 만약



가장 상단의 call 함수를 아래 처럼 변경한다면


        public void call(int first)

        {

            Console.WriteLine(first);

        }




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
 
namespace Test
{
    public class Program
    {
 
 
        public void call(int first)
        {
            Console.WriteLine(first);
        }
 
 
        public void call(int first, int second=30)
        {
            Console.WriteLine(first+second);
        }
 
 
        static void Main()
        {
            int dd = 30;
            Program pi = new Program();
            pi.call(second: dd, first: 20);                //50
            pi.call(first: 20, second:30);                 //22
 
 
            pi.call(30);                        //public void call(int third) 이 호출 됨
 
            pi.call(first: 30);                 //public void call(int first)   이 호출됨!!!!!!!!
 
            pi.call(first: 30, second:70);     //public void call(int first, int second = 30)   이 호출됨
 
pi.call( 30, second: 70); //public void call(int first, int second = 30) 이 호출됨

//pi.call(first: 30, 70); //7.2 버전부터..
 
        }
 
    }
}
 

cs


반응형
반응형



참조로 인수 전달 Ref

메서드의 매개 변수 목록에 사용되는 경우 ref 키워드는 인수가 값이 아니라 참조로 전달됨을 나타냅니다. 인수를 참조로 전달하는 경우 호출된 메서드의 인수 변경 내용이 호출 메서드에 반영됩니다. 예를 들어 호출자가 지역 변수 식 또는 배열 요소 액세스 식을 전달하는 경우 호출된 메서드에서 ref 매개 변수가 참조하는 개체를 바꾸면 메서드 반환 시 호출자의 지역 변수 또는 배열 요소가 새 개체를 참조합니다.



참고

참조로 전달의 개념과 참조 형식의 개념을 혼동해서는 안 됩니다. 이 두 개념은 서로 다릅니다. 메서드 매개 변수는 값 형식이든 참조 형식이든 관계없이 ref를 통해 수정할 수 있으며, 참조로 전달되는 경우 값 형식은 boxing되지 않습니다.

ref 매개 변수를 사용하려면 다음 예제에 나와 있는 것처럼 메서드 정의와 호출 메서드가 모두 ref 키워드를 명시적으로 사용해야 합니다.


void Method(ref int refArgument) { refArgument = refArgument + 44; } int number = 1; Method(ref number); Console.WriteLine(number); // Output: 45



ref 또는 in 매개 변수로 전달하는 인수는 전달 전에 초기화해야 합니다. 이러한 방식은 인수를 전달하기 전에 명시적으로 초기화할 필요가 없는 out 매개 변수와는 다릅니다.

클래스의 멤버는 refin 또는 out만 다른 서명을 포함할 수 없습니다. 특정 형식의 두 멤버가 하나는 ref 매개 변수를 포함하고 다른 하나는 out 또는 in 매개 변수를 포함한다는 것 외에는 차이가 없으면 컴파일러 오류가 발생합니다. 예를 들어 다음 코드는 컴파일되지 않습니다.

class CS0663_Example { // Compiler error CS0663: "Cannot define overloaded // methods that differ only on ref and out". public void SampleMethod(out int i) { } public void SampleMethod(ref int i) { } }



그러나 다음 예제에 나와 있는 것처럼 메서드 하나에는 refin 또는 out 매개 변수가 포함되어 있고 다른 하나에는 값 매개 변수가 포함되어 있으면 메서드를 오버로드할 수 있습니다.

class RefOverloadExample { public void SampleMethod(int i) { } public void SampleMethod(ref int i) { } }


참조로 인수 전달: 예제

앞의 예제에서는 값 형식을 참조로 전달합니다. ref 키워드를 사용하여 참조 형식을 참조로 전달할 수도 있습니다. 참조 형식을 참조로 전달하는 경우 호출된 메서드는 참조 매개 변수가 호출자에서 참조하는 개체를 바꿀 수 있습니다. 개체의 저장 위치는 참조 매개 변수의 값으로 메서드에 전달됩니다. 매개 변수의 저장 위치에서 값을 변경하여 새 개체를 가리키도록 하면 호출자가 참조하는 저장 위치도 변경됩니다. 다음 예제에서는 참조 형식 인스턴스를 ref 매개 변수로 전달합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System;
 
public class MyClass
{
 
    class Product
    {
        public Product(string name, int newID)
        {
            ItemName = name;
            ItemID = newID;
        }
 
        public string ItemName { get; set; }
        public int ItemID { get; set; }
    }
 
    private static void ModifyProductsByReference()
    {
        // Declare an instance of Product and display its initial values.
        Product item = new Product("Fasteners"54321);
        System.Console.WriteLine("Original values in Main.  Name: {0}, ID: {1}\n",
            item.ItemName, item.ItemID);
 
        // Pass the product instance to ChangeByReference.
        ChangeByReference(ref item);
        System.Console.WriteLine("Back in Main.  Name: {0}, ID: {1}\n",
            item.ItemName, item.ItemID);
    }
 
    private static void ChangeByReference(ref Product itemRef)
    {
        // Change the address that is stored in the itemRef parameter.   
        itemRef = new Product("Stapler"99999);
 
        // You can change the value of one of the properties of
        // itemRef. The change happens to item in Main as well.
        itemRef.ItemID = 12345;
    }
 
    static void Main(string[] args)
    {
        ModifyProductsByReference();
    }
}
 



result : 

Original values in Main.  Name: Fasteners, ID: 54321

Back in Main.  Name: Stapler, ID: 12345



참조 반환 값

참조 반환 값(또는 ref return)은 메서드가 호출자에게 참조로 반환하는 값입니다. 즉, 호출자가 메서드에서 반환된 값을 수정할 수 있으며 해당 변경 내용이 메서드를 포함하는 개체의 상태에 반영됩니다.

참조 반환 값은 ref 키워드를 사용하여 정의됩니다.

  • 메서드 시그니처에서. 예를 들어 다음 메서드 시그니처는 GetCurrentPrice 메서드가 Decimal 값을 참조로 반환함을 나타냅니다.

public ref decimal GetCurrentValue()


  • 메서드의 return 문에서 반환된 return 토큰과 변수 간에. 예:

return ref DecimalArray[0];


호출자가 개체 상태를 수정하려면 참조 반환 값을 참조 로컬로 명시적으로 정의된 변수에 저장해야 합니다.


참조 로컬

참조 지역 변수는 return ref을 사용하여 반환된 값을 참조하는 데 사용됩니다. 참조 지역 변수를 초기화하고 참조 반환 값에 할당해야 합니다. 참조 로컬 값의 수정 내용은 메서드가 값을 참조로 반환하는 개체 상태에 반영됩니다.

변수 선언 앞, 값을 참조로 반환하는 메서드 호출 직전에 ref 키워드를 사용하여 참조 로컬을 정의합니다.

예를 들어 다음 문은 GetEstimatedValue 메서드에서 반환되는 참조 로컬 값을 정의합니다.


ref decimal estValue = ref Building.GetEstimatedValue();


동일한 방법으로 참조로 값에 액세스할 수 있습니다. 경우에 따라 참조로 값에 액세스하면 비용이 많이 들 수 있는 복사 작업을 피함으로써 성능이 향상됩니다. 예를 들어, 다음 명령문은 값을 참조하는 데 사용되는 참조 로컬 값을 정의하는 방법을 보여줍니다.

ref VeryLargeStruct reflocal = ref veryLargeStruct;

두 예에서 ref 키워드는 두 위치에 모두 사용해야 합니다. 그렇지 않으면 컴파일러 오류 CS8172, "값을 사용하여 참조 형식 변수를 초기화할 수 없습니다."가 생성됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
 
public class MyClass
{
 
    public class Book
    {
        public string Author;
        public string Title;
    }
 
    public class BookCollection
    {
        private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },
                        new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }
                       };
        private Book nobook = null;
 
        public ref Book GetBookByTitle(string title)
        {
            for (int ctr = 0; ctr < books.Length; ctr++)
            {
                if (title == books[ctr].Title)
                    return ref books[ctr];
            }
            return ref nobook;
        }
 
        public void ListBooks()
        {
            foreach (var book in books)
            {
                Console.WriteLine($"{book.Title}, by {book.Author}");
            }
            Console.WriteLine();
        }
    }
 
    static void Main(string[] args)
    {
        var bc = new BookCollection();
        bc.ListBooks();
 
        ref Book book = ref  bc.GetBookByTitle("Call of the Wild, The");
        //Book book = bc.GetBookByTitle("Call of the Wild, The");
        if (book != null)
            book = new Book { Title = "Republic, The", Author = "Plato" };
        bc.ListBooks();
    }
}
 


호출자가 GetBookByTitle 메서드에서 참조 로컬로 반환된 값을 저장하는 경우 호출자가 반환 값을 변경하면 다음 예제와 같이 BookCollection 개체에 변경 내용이 반영됩니다.


위의 예제 결과는 

Call of the Wild, The, by Jack London

Tale of Two Cities, A, by Charles Dickens


Republic, The, by Plato

Tale of Two Cities, A, by Charles Dickens


이긴 하지만  2017 community 버전에 default 에선 아래 주석 을 지운다고하여 에러가 나진않는다(기존 위에 한줄은 주석처리)

//ref Book book = ref  bc.GetBookByTitle("Call of the Wild, The");
Book book = bc.GetBookByTitle("Call of the Wild, The");

대신 결과는 값 형식 복사가 일어나게 됨으로 다음처럼 나타나게 된다(컴파일 에러가 나진 않음)

Call of the Wild, The, by Jack London

Tale of Two Cities, A, by Charles Dickens


Call of the Wild, The, by Jack London

Tale of Two Cities, A, by Charles Dickens






가변인자 params


params 키워드를 사용하면 가변 개수의 인수를 사용하는 메서드 매개 변수를 지정할 수 있습니다.

매개 변수 선언이나 지정된 형식의 인수 배열에 지정된 형식의 쉼표로 구분된 인수 목록을 보낼 수 있습니다. 인수를 보내지 않을 수도 있습니다. 인수를 보내지 않는 경우 params 목록의 길이는 0입니다.

메서드 선언에서 params 키워드 뒤에는 추가 매개 변수가 허용되지 않으며, params 키워드 하나만 메서드 선언에 사용할 수 있습니다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
using System;
 
public class MyClass
{
    public static void UseParams(params int[] list)
    {
        for (int i = 0; i < list.Length; i++)
        {
            Console.Write(list[i] + " ");
        }
        Console.WriteLine();
    }
 
    public static void UseParams2(params object[] list)
    {
        Console.WriteLine(list.GetType() );
        if(list.Length >= 1)
        {
            Console.WriteLine(list[0].GetType());
 
 
            var test = list[0as int[];
            if(test!=null)
            {
                Console.WriteLine("\t" + test[0].GetType());
            }
            
        }
        
        for (int i = 0; i < list.Length; i++)
        {
            Console.Write(list[i] + " ");
        }
        Console.WriteLine();
    }
 
 
 
    static void Main()
    {
        
 
 
        // You can send a comma-separated list of arguments of the 
        // specified type.
        UseParams(1234);
        UseParams2(1'a'"test");
 
        // A params parameter accepts zero or more arguments.
        // The following calling statement displays only a blank line.
        UseParams2();
 
        // An array argument can be passed, as long as the array
        // type matches the parameter type of the method being called.
        int[] myIntArray = { 56789 };
        UseParams(myIntArray);
        Console.WriteLine(typeof(int[]));
        
 
        object[] myObjArray = { 2'b'"test""again" };
        UseParams2(myObjArray);
 
        Console.WriteLine(typeof(object[]));
 
        // The following call causes a compiler error because the object
        // array cannot be converted into an integer array.
        //UseParams(myObjArray);
 
        // The following call does not cause an error, but the entire 
        // integer array becomes the first element of the params array.
        // int[] 전체가 object 가 되기 때문에 에러가 나지 않는다
        UseParams2(myIntArray);
    }
}
/*
Output:
1 2 3 4
System.Object[]
System.Int32
1 a test
System.Object[]
5 6 7 8 9
System.Int32[]
System.Object[]
System.Int32
2 b test again
System.Object[]
System.Object[]
System.Int32[]
        System.Int32
*/
 

.







out


out 키워드를 사용하면 참조를 통해 인수를 전달할 수 있습니다. 이러한 방식은 ref 키워드와 비슷합니다. 단, ref의 경우에는 변수를 전달하기 전에 초기화해야 합니다. in이 호출된 메서드에서 인수 값 수정을 허용하지 않는 것을 제외하고 in 키워드와도 같습니다. out 매개 변수를 사용하려면 메서드 정의와 호출 메서드가 모두 명시적으로 out 키워드를 사용해야 합니다. 예:



int initializeInMethod; OutArgExample(out initializeInMethod); Console.WriteLine(initializeInMethod); // value is now 44 void OutArgExample(out int number) { number = 44; }


out 인수로 전달되는 변수는 메서드 호출에서 전달되기 전에 초기화할 필요가 없지만 호출된 메서드는 메서드가 반환되기 전에 값을 할당해야 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
 
public class MyClass
{
 
    public void SampleMethod(out int i)
    {
        //아래 주석을 풀면 에러 안남
        //오류 CS0177  제어가 현재 메서드를 벗어나기 전에 'i' out 매개 변수를 할당해야 합니다.
        //i = 3;
    }
 
    //이 전체 주석을 풀면 컴파일 에러
    //'MyClass'은(는) 매개 변수 한정자 'ref' 및 'out'만 다른 오버로드된 메서드을(를) 정의할 수 없습니다.
    /*
    public void SampleMethod(ref int i)
    {
    }*/
    static void Main()
    {
 
 
    }
}
 





out 인수 선언

메서드가 여러 값을 반환하도록 하려는 경우 out 인수를 사용하여 메서드를 선언하면 유용합니다. 다음 예제에서는 out을 사용하여 단일 메서드 호출로 3개 변수를 반환합니다. 세 번째 인수는 null에 할당됩니다. 따라서 메서드가 값을 선택적으로 반환할 수 있습니다.


void Method(out int answer, out string message, out string stillNull) { answer = 44; message = "I've been returned"; stillNull = null; } int argNumber; string argMessage, argDefault; Method(out argNumber, out argMessage, out argDefault); Console.WriteLine(argNumber); Console.WriteLine(argMessage); Console.WriteLine(argDefault == null);




C# 7.0부터 별도 변수 선언이 아니라 메서드 호출의 인수 목록에서 out 변수를 선언할 수 있습니다. 이렇게 하면 보다 간결하고 읽기 쉬운 코드가 생성되며 메서드 호출 전에 실수로 변수에 값이 할당되는 경우를 방지할 수 있습니다. 다음 예제는 Int32.TryParse 메서드 호출에서 number 변수를 정의한다는 점을 제외하고 이전 예제와 비슷합니다.


string numberAsString = "1640"; if (Int32.TryParse(numberAsString, out int number)) Console.WriteLine($"Converted '{numberAsString}' to {number}"); else Console.WriteLine($"Unable to convert '{numberAsString}'"); // The example displays the following output: // Converted '1640' to 1640



앞의 예제에서 number 변수는 int로 강력하게 형식화됩니다. 다음 예제와 같이 암시적 형식 지역 변수를 선언할 수도 있습니다.


string numberAsString = "1640"; if (Int32.TryParse(numberAsString, out var number)) Console.WriteLine($"Converted '{numberAsString}' to {number}"); else Console.WriteLine($"Unable to convert '{numberAsString}'"); // The example displays the following output: // Converted '1640' to 1640







(호출된 메서드에서 인수를 수정하지 못하는) in




in 키워드를 사용하면 참조를 통해 인수를 전달할 수 있습니다. 이 키워드는 호출된 메서드에서 in 인수를 수정할 수 없다는 점을 제외하고 ref 또는 out 키워드와 유사합니다. ref 인수는 수정할 수 있지만 out 인수는 호출자가 수정해야 하며, 해당 수정 사항은 호출 컨텍스트에서 식별 가능합니다.


int readonlyArgument = 44; InArgExample(readonlyArgument); Console.WriteLine(readonlyArgument); // value is still 44 void InArgExample(in int number) { // Uncomment the following line to see error CS8331 //number = 19; }



in 인수로 전달되는 변수는 메서드 호출에서 전달되기 전에 초기화되어야 합니다. 그러나 호출된 메서드는 값을 할당하거나 인수를 수정하지 않을 수 있습니다.

inref 및 out 키워드는 서로 다른 런타임 동작을 수행하지만 컴파일 시간에 메서드 시그니처의 일부로 간주되지는 않습니다. 따라서 메서드 하나는 ref 또는 in 인수를 사용하고 다른 하나는 out 인수를 사용한다는 것 외에는 차이점이 없으면 메서드를 오버로드할 수 없습니다. 예를 들어 다음 코드는 컴파일되지 않습니다.


class CS0663_Example { // Compiler error CS0663: "Cannot define overloaded // methods that differ only on in, ref and out". public void SampleMethod(in int i) { } public void SampleMethod(ref int i) { } }


in의 존재에 기반한 오버로딩이 허용됩니다.

class InOverloads { public void SampleMethod(in int i) { } public void SampleMethod(int i) { } }



in 매개 변수를 사용하여 메서드를 정의하면 잠재적인 성능 최적화가 이루어집니다. 일부 struct 형식 인수는 크기가 클 수 있으며 긴밀한 루프 또는 중요한 코드 경로에서 메서드를 호출할 때 해당 구조를 복사하는 비용이 중요합니다. 메서드는 호출된 메서드가 인수의 상태를 수정하지 않으므로 in 매개 변수를 선언하여 해당 인수가 참조로 안전하게 전달될 수 있음을 지정합니다. 이러한 인수를 참조로 전달하면 (잠재적으로) 비용이 많이 드는 복사본을 방지할 수 있습니다.





오버로드 해결 규칙

in 인수에 대한 동기를 이해하여 값과 in 인수로 메서드의 오버로드 해결 규칙을 이해할 수 있습니다. in 매개 변수를 사용하여 메서드를 정의하면 잠재적인 성능 최적화가 이루어집니다. 일부 struct 형식 인수는 크기가 클 수 있으며 긴밀한 루프 또는 중요한 코드 경로에서 메서드를 호출할 때 해당 구조를 복사하는 비용이 중요합니다. 메서드는 호출된 메서드가 인수의 상태를 수정하지 않으므로 in 매개 변수를 선언하여 해당 인수가 참조로 안전하게 전달될 수 있음을 지정합니다. 이러한 인수를 참조로 전달하면 (잠재적으로) 비용이 많이 드는 복사본을 방지할 수 있습니다.

호출 사이트의 인수에 in을 지정하는 것은 일반적으로 선택 사항입니다. 값으로 인수를 전달하고 in 한정자를 사용하여 인수를 전달하는 것 사이에는 의미 체계상 차이가 없습니다. 호출 사이트의 in 한정자는 인수 값이 변경될 수 있음을 나타내지 않아도 되므로 선택 사항입니다. 호출 사이트에서 in 한정자를 명시적으로 추가하여 인수가 값이 아닌 참조로 전달되도록 합니다. 명시적으로 in을 사용하는 경우 다음과 같은 두 가지 효과가 있습니다.

먼저 호출 사이트에서 in을 지정하면 컴파일러가 일치하는 in 매개 변수로 정의된 메서드를 선택하게 됩니다. 그렇지 않으면 두 메서드가 in이 있을 때만 다른 경우 by 값 오버로드가 더 적합합니다.

둘째, in을 지정하면 참조로 인수를 전달할 의사가 있음을 선언하는 것입니다. in에 사용된 인수는 직접 참조할 수 있는 위치를 나타내야 합니다. out 및 ref 인수에는 동일한 일반 규칙이 적용됩니다. 상수, 일반 속성 또는 값을 생성하는 다른 식은 사용할 수 없습니다.그렇지 않으면 호출 사이트에서 in을 생략할 경우 메서드에 대한 읽기 전용 참조로 전달할 임시 변수를 만들 수 있도록 컴파일러에 알립니다. 컴파일러는 in 인수를 사용하여 몇 가지 제한 사항을 해결하기 위해 임시 변수를 만듭니다.

  • 임시 변수는 컴파일 시간 상수를 in 매개 변수로 허용합니다.
  • 임시 변수는 속성 또는 in 매개 변수에 대한 다른 식을 허용합니다.
  • 임시 변수는 인수 형식에서 매개 변수 형식으로의 암시적 변환이 있는 경우 인수를 허용합니다.

앞의 모든 인스턴스에서 컴파일러는 상수, 속성 또는 다른 식의 값을 저장하는 임시 변수를 만듭니다.

다음 코드에서는 이러한 규칙을 보여줍니다.


static void Method(in int argument) { // implementation removed } Method(5); // OK, temporary variable created. Method(5L); // CS1503: no implicit conversion from long to int short s = 0; Method(s); // OK, temporary int created with the value 0 Method(in s); // CS1503: cannot convert from in short to in int int i = 42; Method(i); // passed by readonly reference Method(in i); // passed by readonly reference, explicitly using `in`




이제 by 값 인수를 사용하는 다른 메서드를 사용할 수 있다고 가정하겠습니다. 결과는 다음 코드와 같이 변경됩니다.



static void Method(int argument) { // implementation removed } static void Method(in int argument) { // implementation removed } Method(5); // Calls overload passed by value Method(5L); // CS1503: no implicit conversion from long to int short s = 0; Method(s); // Calls overload passed by value. Method(in s); // CS1503: cannot convert from in short to in int int i = 42; Method(i); // Calls overload passed by value Method(in i); // passed by readonly reference, explicitly using `in`









ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/params

ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/out-parameter-modifier

ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/in-parameter-modifier

ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/ref



이미지컷



반응형
반응형


[GetUpperBound, GetLowerBound]




구문 소개에 앞서 배열 차원 인덱스 반환 함수 설명 (차원 숫자가 클 수록 더 안쪽에 있는 차원을 말한다)

public int GetUpperBound(
	int dimension
)

GetUpperBound(0)배열의 첫 번째 차원에서 마지막 인덱스를 반환 하 고 GetUpperBound(Rank - 1) 마지막 배열의 마지막 차원 인덱스를 반환 합니다.






Copy(Array, Array, Int32)  : 인자들은 첫번째 배열, 두번째 인자, 마지막 숫자는 인덱스 위치까지 복사될 index

System_CAPS_pubmethodSystem_CAPS_staticCopy(Array, Array, Int32)

Array의 요소 범위를 첫 번째 요소부터 복사하여 다른 Array에 첫 번째 요소부터 붙여넣습니다. 길이가 32비트 정수로 지정되어 있습니다.

System_CAPS_pubmethodSystem_CAPS_staticCopy(Array, Array, Int64)

Array의 요소 범위를 첫 번째 요소부터 복사하여 다른 Array에 첫 번째 요소부터 붙여넣습니다. 길이가 64비트 정수로 지정되어 있습니다.

System_CAPS_pubmethodSystem_CAPS_staticCopy(Array, Int32, Array, Int32, Int32)

Array의 요소 범위를 지정한 소스 인덱스부터 복사하여 지정된 대상 인덱스부터 시작하는 다른 Array에 붙여 넣습니다. 길이와 인덱스가 32비트 정수로 지정되어 있습니다.

System_CAPS_pubmethodSystem_CAPS_staticCopy(Array, Int64, Array, Int64, Int64)

Array의 요소 범위를 지정한 소스 인덱스부터 복사하여 지정된 대상 인덱스부터 시작하는 다른 Array에 붙여 넣습니다. 길이와 인덱스가 64비트 정수로 지정되어 있습니다.

System_CAPS_pubmethodCopyTo(Array, Int32)

현재 1차원 배열의 모든 요소를 지정된 대상 배열 인덱스부터 시작하여 지정된 1차원 배열에 복사합니다. 인덱스가 32비트 정수로 지정되어 있습니다.

System_CAPS_pubmethodCopyTo(Array, Int64)

현재 1차원 배열의 모든 요소를 지정된 대상 배열 인덱스부터 시작하여 지정된 1차원 배열에 복사합니다. 인덱스가 64비트 정수로 지정되어 있습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
using System;
public class SamplesArray
{
 
    public static void Main()
    {
 
        // Creates and initializes a new integer array and a new Object array.
        int[] myIntArray = new int[5] { 12345 };
        Object[] myObjArray = new Object[5] { 2627282930 };
 
        // Prints the initial values of both arrays.
        Console.WriteLine("Initially,");
        Console.Write("integer array:");
        PrintValues(myIntArray);
        Console.Write("Object array: ");
        PrintValues(myObjArray);
 
        // Copies the first two elements from the integer array to the Object array.
        System.Array.Copy(myIntArray, myObjArray, 2); //처음 두개만 복사
 
        // Prints the values of the modified arrays.
        Console.WriteLine("\nAfter copying the first two elements of the integer array to the Object array,");
        Console.Write("integer array:");
        PrintValues(myIntArray);
        Console.Write("Object array: ");
        PrintValues(myObjArray);
 
        // Copies the last two elements from the Object array to the integer array.
//마지막 두개 복사
        System.Array.Copy(myObjArray, myObjArray.GetUpperBound(0- 1, myIntArray, myIntArray.GetUpperBound(0- 12);
 
        // Prints the values of the modified arrays.
        Console.WriteLine("\nAfter copying the last two elements of the Object array to the integer array,");
        Console.Write("integer array:");
        PrintValues(myIntArray);
        Console.Write("Object array: ");
        PrintValues(myObjArray);
    }
 
 
    public static void PrintValues(Object[] myArr)
    {
        foreach (Object i in myArr)
        {
            Console.Write("\t{0}", i);
        }
        Console.WriteLine();
    }
 
    public static void PrintValues(int[] myArr)
    {
        foreach (int i in myArr)
        {
            Console.Write("\t{0}", i);
        }
        Console.WriteLine();
    }
}
/* 
This code produces the following output.
Initially,
integer array:  1       2       3       4       5
Object array:   26      27      28      29      30
After copying the first two elements of the integer array to the Object array,
integer array:  1       2       3       4       5
Object array:   1       2       28      29      30
After copying the last two elements of the Object array to the integer array,
integer array:  1       2       3       29      30
Object array:   1       2       28      29      30
*/
 

cs



ref : https://msdn.microsoft.com/ko-kr/library/system.array(v=vs.110).aspx

반응형
반응형

배열에는 최대 32 차원 초과 있을 수 있습니다.


클래스와 달리는 System.Collections 네임 스페이스, Array 용량이 고정 합니다. 용량을 늘리려면 새 만들어야 Array 필요한 용량으로 개체, 이전에서 요소를 복사 Array 새 레코드로 개체를 삭제 하면 이전 Array합니다.

기본적으로의 최대 크기는 Array 은 2gb (기가바이트)입니다. 64 비트 환경에서 크기 제한을 설정 하 여 방지할 수 있습니다는 enabled 특성에는gcAllowVeryLargeObjects 구성 요소를 true 런타임 환경에서 합니다. 그러나 배열의 지정 된 차원 
(바이트 배열 및 단일 바이트 구조의 배열에 대 한 0X7FFFFFC7) 에 0X7FEFFFFF의 최대 인덱스는 총 4 십억 요소로 제한 수 있습니다.



배열에 둘 이상의 차원이 있을 수 있습니다. 예를 들어 다음 선언은 행 4개, 열 2개의 2차원 배열을 만듭니다.

int[,] array = new int[4, 2];

다음 선언은 세 가지 차원 4, 2, 3의 배열을 만듭니다.


int[, ,] array1 = new int[4, 2, 3];

배열 초기화

다음 예제와 같이 선언 시 배열을 초기화할 수 있습니다.


// Two-dimensional array.
int[,] array2D = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// The same array with dimensions specified.
int[,] array2Da = new int[4, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// A similar array with string elements.
string[,] array2Db = new string[3, 2] { { "one", "two" }, { "three", "four" },
                                        { "five", "six" } };

// Three-dimensional array.
int[, ,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } }, 
                                 { { 7, 8, 9 }, { 10, 11, 12 } } };
// The same array with dimensions specified.
int[, ,] array3Da = new int[2, 2, 3] { { { 1, 2, 3 }, { 4, 5, 6 } }, 
                                       { { 7, 8, 9 }, { 10, 11, 12 } } };

// Accessing array elements.
System.Console.WriteLine(array2D[0, 0]);
System.Console.WriteLine(array2D[0, 1]);
System.Console.WriteLine(array2D[1, 0]);
System.Console.WriteLine(array2D[1, 1]);
System.Console.WriteLine(array2D[3, 0]);
System.Console.WriteLine(array2Db[1, 0]);
System.Console.WriteLine(array3Da[1, 0, 1]);
System.Console.WriteLine(array3D[1, 1, 2]);

// Getting the total count of elements or the length of a given dimension.
var allLength = array3D.Length;
var total = 1;
for (int i = 0; i < array3D.Rank; i++) {
    total *= array3D.GetLength(i);
}
System.Console.WriteLine("{0} equals {1}", allLength, total);

// Output:
// 1
// 2
// 3
// 4
// 7
// three
// 8
// 12
// 12 equals 12


차수를 지정하지 않고 배열을 초기화할 수도 있습니다.


int[,] array4 = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };

초기화하지 않고 배열 변수를 선언하도록 선택할 경우 new 연산자를 사용하여 변수에 배열을 할당해야 합니다. new 사용은 다음 예제에서 확인할 수 있습니다.


int[,] array5;
array5 = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };   // OK
//array5 = {{1,2}, {3,4}, {5,6}, {7,8}};   // Error


다음 예제에서는 특정 배열 요소에 값을 할당합니다.


array5[2, 1] = 25;

마찬가지로, 다음 예제에서는 특정 배열 요소의 값을 가져와 elementValue 변수에 할당합니다.


int elementValue = array5[2, 1];

다음 코드 예제에서는 가변 배열을 제외하고 배열 요소를 기본 값으로 초기화합니다.


int[,] array6 = new int[10, 10];







구문 소개에 앞서 배열 차원 인덱스 반환 함수 설명 (차원 숫자가 클 수록 더 안쪽에 있는 차원을 말한다)

public int GetUpperBound(
	int dimension
)

GetUpperBound(0)배열의 첫 번째 차원에서 마지막 인덱스를 반환 하 고 GetUpperBound(Rank - 1) 마지막 배열의 마지막 차원 인덱스를 반환 합니다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using static System.Console;
 
namespace intel
{
    public class test1
    {
        public static void Main(string[] args)
        {
 
            // Create a one-dimensional integer array.
            int[] integers = { 2468101214161820 };
            // Get the upper and lower bound of the array.
            int upper = integers.GetUpperBound(0);
            int lower = integers.GetLowerBound(0);
            Console.WriteLine("Elements from index {0} to {1}:", lower, upper);
            // Iterate the array.
            for (int ctr = lower; ctr <= upper; ctr++)
                Console.Write("{0}{1}{2}", ctr == lower ? "   " : "",
                                          integers[ctr],
                                          ctr < upper ? ", " : Environment.NewLine);
 
            Console.WriteLine();
 
 
            // Create a two-dimensional integer array.
            int[,] integers2d = { 
                {24}, 
                {39}, 
                {416}, 
                {525}, 
                {636}, 
                {749}, 
                {864}, 
                {981} };
            
            // Get the number of dimensions.                               
            int rank = integers2d.Rank;
            Console.WriteLine("Number of dimensions: {0}", rank);
            for (int ctr = 0; ctr < integers2d.Rank - 1; ctr++)
            {
                Console.WriteLine("   Dimension {0}: from {1} to {2}", ctr, integers2d.GetLowerBound(ctr), integers2d.GetUpperBound(ctr));
            }
                
 
 
            // Iterate the 2-dimensional array and display its values.
            Console.WriteLine("   Values of array elements:");
            for (int outer = integers2d.GetLowerBound(0); outer <= integers2d.GetUpperBound(0); outer++)
            {
                for (int inner = integers2d.GetLowerBound(1); inner <= integers2d.GetUpperBound(1); inner++)
                {
                    Console.Write("      {3}{0}, {1}{4} = {2}", outer, inner, integers2d.GetValue(outer, inner), "{""}");
                }
                Console.WriteLine("");
            }
 
        }
 
    }
}
 
 

cs




결과

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Elements from index 0 to 9:
   2, 4, 6, 8, 10, 12, 14, 16, 18, 20
 
Number of dimensions: 2
   Dimension 0: from 0 to 7
   Values of array elements:
      {0, 0} = 2      {0, 1} = 4
      {1, 0} = 3      {1, 1} = 9
      {2, 0} = 4      {2, 1} = 16
      {3, 0} = 5      {3, 1} = 25
      {4, 0} = 6      {4, 1} = 36
      {5, 0} = 7      {5, 1} = 49
      {6, 0} = 8      {6, 1} = 64
      {7, 0} = 9      {7, 1} = 81
cs







ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/arrays/multidimensional-arrays

ref : https://msdn.microsoft.com/ko-kr/library/system.array(v=vs.110).aspx

ref : https://msdn.microsoft.com/ko-kr/library/system.array.getupperbound(v=vs.110).aspx

반응형
반응형

Nullable 형식 사용




nullable 형식은 기본 형식의 모든 값과 추가 null 값을 나타낼 수 있습니다. nullable 형식은 다음과 같은 두 가지 방법 중 하나로 선언됩니다.

System.Nullable<T> variable

또는

T? variable

T는 nullable 형식의 기본 형식입니다. T는 struct를 비롯한 모든 값 형식일 수 있으나, 참조 형식일 수는 없습니다.


object? sdf;  //컴파일 오류


nullable 형식을 사용할 수 있는 경우의 예를 들기 위해 일반 부울 변수가 두 가지 값 true와 false를 가질 수 있는 방법을 고려합니다. “정의되지 않음”을 의미하는 값은 없습니다. 많은 프로그래밍 응용 프로그램(특히, 데이터베이스 상호 작용)에서 변수는 정의되지 않은 상태로 발생할 수 있습니다. 예를 들어 데이터베이스의 필드는 true 또는 false 값을 포함할 수 있지만, 전혀 값을 포함하지 않을 수도 있습니다. 마찬가지로, 초기화되지 않았음을 나타내기 위해 참조 형식을 null로 설정할 수 있습니다.

이 차이로 인해 상태 정보, 특수 값 사용 등을 저장하는 데 사용되는 추가 변수와 관련한 추가 프로그래밍 작업이 발생할 수 있습니다. C#에서는 nullable 형식 한정자를 사용하여 정의되지 않은 값을 나타내는 값 형식 변수를 만들 수 있습니다.



nullable 형식의 예

nullable 형식에 대한 기준으로 모든 값 형식을 사용할 수 있습니다. 예:


1
2
3
4
5
int? i = 10;
double? d1 = 3.14;
bool? flag = null;
char? letter = 'a';
int?[] arr = new int?[10];
cs

nullable 형식의 멤버

nullable 형식의 각 인스턴스에는 다음과 같은 두 개의 public 읽기 전용 속성이 포함됩니다.

  • HasValue

    HasValue는 bool 형식입니다. 변수가 null이 아닌 값을 포함한 경우 true로 설정됩니다.

  • Value

    Value는 기본 형식과 같은 형식입니다. HasValue가 true이면 Value에는 의미 있는 값이 포함됩니다. HasValue가 false이면 Value에서는 InvalidOperationException을 throw합니다.

이 예제에서 HasValue 멤버는 변수를 표시하려고 하기 전에 변수가 값을 포함하는지를 테스트하는 데 사용됩니다.

1
2
3
4
5
6
7
8
9
10
int? x = 10;
if (x.HasValue)
{
    System.Console.WriteLine(x.Value);
}
else
{
    System.Console.WriteLine("Undefined");
}
 

cs


값에 대한 테스트는 다음 예제처럼 수행할 수도 있습니다.


1
2
3
4
5
6
7
8
9
int? y = 10;
if (y != null)
{
    System.Console.WriteLine(y.Value);
}
else
{
    System.Console.WriteLine("Undefined");
}



명시적 변환

nullable 형식은 캐스트를 사용하여 명시적으로 또는 Value 속성을 사용하여 일반 형식으로 캐스팅할 수 있습니다. 예:


1
2
3
4
5
int? n = null;
 
//int m1 = n;      // Will not compile.
int m2 = (int)n;   // Compiles, but will create an exception if n is null.
int m3 = n.Value;  // Compiles, but will create an exception if n is null.


두 데이터 형식 간에 사용자 정의 변환이 정의된 경우 이러한 데이터 형식의 nullable 버전에도 같은 변환을 사용할 수 있습니다.

암시적 변환

nullable 형식의 변수는 다음 예제와 같이 null 키워드를 사용하여 null로 설정할 수 있습니다.

int? n1 = null;


일반 형식에서 nullable 형식으로의 변환은 암시적입니다.

int? n2; n2 = 10; // Implicit conversion.


연산자

미리 정의된 단항 및 이항 연산자와 값 형식에 대해 존재하는 모든 사용자 정의 연산자는 nullable 형식에도 사용할 수 있습니다. 이러한 연산자는 피연산자가 null인 경우 null 값을 생성하고, 그렇지 않으면 연산자는 포함된 값을 사용하여 결과를 계산합니다. 예:

1
2
3
4
5
6
int? a = 10;
int? b = null;
 
a++;         // Increment by 1, now a is 11.
= a * 10;  // Multiply by 10, now a is 110.
= a + b;   // Add b, now a is null.
cs

nullable 형식과의 비교를 수행할 때 nullable 형식 중 하나의 값이 null이고 나머지는 null이 아닌 경우 모든 비교는 !=(같지 않음)을 제외하고는 false로 계산됩니다. 특정 비교에서는 false를 반환하고 그 반대의 경우에는 true를 반환한다고 가정하지 않는 것이 중요합니다. 다음 예제에서 10은 null보다 크지 않고, 작지 않고, 같지도 않습니다. num1 != num2만 true로 계산됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
int? num1 = 10;
int? num2 = null;
if (num1 >= num2)
{
    Console.WriteLine("num1 is greater than or equal to num2");
}
else
{
    // This clause is selected, but num1 is not less than num2.
    Console.WriteLine("num1 >= num2 returned false (but num1 < num2 also is false)");
}
 
if (num1 < num2)
{
    Console.WriteLine("num1 is less than num2");
}
else
{
    // The else clause is selected again, but num1 is not greater than
    // or equal to num2.
    Console.WriteLine("num1 < num2 returned false (but num1 >= num2 also is false)");
}
 
if (num1 != num2)
{
    // This comparison is true, num1 and num2 are not equal.
    Console.WriteLine("Finally, num1 != num2 returns true!");
}
 
// Change the value of num1, so that both num1 and num2 are null.
num1 = null;
if (num1 == num2)
{
    // The equality comparison returns true when both operands are null.
    Console.WriteLine("num1 == num2 returns true when the value of each is null");
}
 
/* Output:
 * num1 >= num2 returned false (but num1 < num2 also is false)
 * num1 < num2 returned false (but num1 >= num2 also is false)
 * Finally, num1 != num2 returns true!
 * num1 == num2 returns true when the value of each is null
 */



둘 다 null인 두 nullable 형식의 같음 비교는 true로 계산됩니다.

?? 연산자

?? 연산자는 nullable 형식이 nullable 형식이 아닌 형식에 할당된 경우 반환되는 기본값을 정의합니다.

말이 좀 이상한데 쉽게 말한다면 c가 null 인경우 -1 을 ? 아닌 변수 d 에 할당한다(초기화 한다)로 보면 됩니다



int? c = null;

// d = c, unless c is null, in which case d = -1.
int d = c ?? -1;

이 연산자는 여러 nullable 형식에도 사용할 수 있습니다. 예:


아래 같은 경우에는 e 와 f 가 모두 null 임으로 -1 이 g 에 할당됩니다


int? e = null;
int? f = null;

// g = e or f, unless e and f are both null, in which case g = -1.
int g = e ?? f ?? -1;


bool? 형식

bool? nullable 형식은 세 가지 값 truefalse 및 null을 포함할 수 있습니다. 
bool?에서 bool로 캐스팅하는 방법에 대한 자세한 내용은 방법: bool?에서 bool로 안전하게 캐스팅을 참조하세요.

nullable 부울은 SQL에서 사용되는 부울 변수 형식과 유사합니다. & 및 | 연산자에 의해 생성된 결과가 SQL의 삼중값 부울 형식과 일치하도록 다음과 같은 미리 정의된 연산자가 제공됩니다.

bool? operator &(bool? x, bool? y)

bool? operator |(bool? x, bool? y)

다음 표는 이러한 연산자의 결과를 보여 줍니다.

Xyx&yx|y
truetruetruetrue
trueFalsefalsetrue
truenullnulltrue
FalsetrueFalsetrue
FalseFalseFalseFalse
FalsenullFalsenull
nulltruenulltrue
nullFalseFalsenull
nullnullnullnull




ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/nullable-types/using-nullable-types





반응형
반응형
실수형 decimal (128bit) 


이름이 decimal 인데 실수형이다 


큰 데이터를 다룰때 사용된다





decimal 키워드는 128비트 데이터 형식을 나타냅니다. decimal 형식은 부동 소수점 형식보다 전체 자릿수는 크고 범위는 작아서 재무 및 통화 계산에 적합합니다. 다음 표에서는 decimal 형식의 대략적인 범위와 전체 자릿수를 보여 줍니다.

형식근사 범위전체 자릿수.NET 형식
decimal(-7.9 x 1028 ~ 7.9 x 1028) / (100 ~ 1028)28-29개의 유효 자릿수System.Decimal



decimal의 기본값은 0m입니다.

리터럴

숫자 형식의 실수 리터럴이 decimal로 처리되게 하려면 다음과 같이 접미사 m 또는 M을 사용합니다.

C#
decimal myMoney = 300.5m;

m 접미사가 없으면 숫자가 double로 처리되어 컴파일러 오류가 발생합니다.

변환

정수 형식은 암시적으로 decimal로 변환되어 계산 결과가 decimal로 나타납니다. 따라서 접미사를 붙이지 않고 정수 리터럴을 사용하여 decimal 변수를 초기화할 수 있습니다. 예를 들면 다음과 같습니다.

C#
decimal myMoney = 300;

다른 부동 소수점 형식과 decimal 형식 간의 암시적 변환은 없습니다. 따라서 이 두 형식 간의 변환에는 캐스트를 사용해야 합니다. 예:

C#
decimal myMoney = 99.9m;
double x = (double)myMoney;
myMoney = (decimal)x;

또한 같은 식에서 decimal과 숫자 정수 형식을 혼합할 수 있습니다. 그러나 캐스트를 사용하지 않고 decimal과 다른 부동 소수점 형식을 혼합하면 컴파일 오류가 발생합니다.

암시적 숫자 변환에 대한 자세한 내용은 암시적 숫자 변환 표를 참조하세요.

명시적 숫자 변환에 대한 자세한 내용은 명시적 숫자 변환 표를 참조하세요.

decimal 출력 서식 지정

String.Format 메서드를 사용하거나 Console.Write을 호출하는 String.Format() 메서드를 통해 결과의 서식을 지정할 수 있습니다. 통화 서식은 이 문서 뒷부분에 있는 두 번째 예제처럼 표준 통화 서식 문자열 "C" 또는 "c"를 사용하여 지정합니다. String.Format 메서드에 대한 자세한 내용은 String.Format을 참조하십시오.

이 예제에서는 통화 서식 문자열을 사용하여 출력 서식을 지정합니다. x는 소수 자릿수가 $0.99를 초과하기 때문에 반올림됩니다. (통화 서식 때문에 1.00 으로 처리됨 => :C 를 제거 하면 소수부가 모두 표시됩니다)
최대 자릿수를 나타내는 변수 y는 올바른 서식으로 정확하게 표시됩니다.

C#
public class TestDecimalFormat
{
    static void Main()
    {
        decimal x = 0.999m;
        decimal y = 9999999999999999999999999999m;
        Console.WriteLine("My amount = {0:C}", x);
        Console.WriteLine("Your amount = {0:C}", y);
    }
}
/* Output:
    My amount = $1.00
    Your amount = $9,999,999,999,999,999,999,999,999,999.00
*/



ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/decimal



반응형
반응형

object(C# 참조)


object 형식은 .NET Framework에서 Object의 별칭입니다. 

C#의 통합 형식 시스템에서 사용자 정의 및 미리 정의된 참조 형식과 값 형식을 비롯한 모든 형식은 

직접 또는 간접적으로 Object에서 상속합니다. object 형식의 변수에 모든 형식의 값을 할당할 수 있습니다. 

값 형식의 변수가 개체로 변환된 경우 boxed라고 합니다. 

형식 개체의 변수가 값 형식으로 변환된 경우 unboxed라고 합니다. 

자세한 내용은 boxing 및 unboxing을 참조하세요.

다음 샘플은 object 형식의 변수가 모든 데이터 형식의 값을 허용할 수 있는 방법 및 object 형식의 변수가 .NET Framework의 Object에 대해 메서드를 사용할 수 있는 방법을 보여 줍니다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ObjectTest
{
   public int i = 10;
}
 
class MainClass2
{
   static void Main()
   {
      object a;
      a = 1;   // an example of boxing
      Console.WriteLine(a);
      Console.WriteLine(a.GetType());
      Console.WriteLine(a.ToString());
 
      a = new ObjectTest();
      ObjectTest classRef;
      classRef = (ObjectTest)a;
      Console.WriteLine(classRef.i);
   }
}
/* Output
    1
    System.Int32
    1
 * 10
*/



반응형
반응형


String.Format Placeholder/서식


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
97
98
99
100
101
102
 
Decimal pricePerOunce = 17.36m;
String s = String.Format("The current price is {0} per ounce.",
                         pricePerOunce);
// Result: The current price is 17.36 per ounce.
String s = String.Format("The current price is {0:C2} per ounce.",
                         pricePerOunce);
// Result if current culture is en-US:
//      The current price is $17.36 per ounce.
 
 
 
 
//String.Format형식 문자열 뒤에 하나 이상의 개체 또는 문자열로 변환 되며 형식 문자열에서 지정된 된 위치에 삽입 하는 
//식으로 시작 합니다. 예:
decimal temp = 20.4m;
string s = String.Format("The temperature is {0}°C.", temp);
Console.WriteLine(s);
// Displays 'The temperature is 20.4°C.'
 
//{0} 형식에서 문자열은 형식 항목입니다. 0문자열 값을 해당 위치에 삽입할 개체의 인덱스가입니다. (인덱스 0부터 시작)입니다. 
//삽입 될 개체가 문자열이 아닌 경우 해당 ToString 메서드를 호출 하는 결과 문자열에 삽입 하기 전에 하나를 변환 합니다.
 
 
 
 
string s = String.Format("At {0}, the temperature is {1}°C.",
                         DateTime.Now, 20.4);
// Output similar to: 'At 4/10/2015 9:29:41 AM, the temperature is 20.4°C.'
 
 
 
 
//서식 지정 제어
//개체의 서식 지정 하는 방법을 제어 하는 형식 문자열 형식 항목의 인덱스를 따를 수 있습니다. 
//예를 들어 {0:d} 개체 목록에서 첫 번째 개체 "d" 형식 문자열에 적용 됩니다. 다음은 단일 개체와 예제 하 고 
//두 항목의 서식을 지정 합니다.
 
string s = String.Format("It is now {0:d} at {0:t}", DateTime.Now);
// Output similar to: 'It is now 4/10/2015 at 10:04 AM'
 
//형식 문자열, 모든 숫자 형식을 포함 한 다양 한 형식 지원 (둘 다 표준 및 사용자 지정 형식 문자열), 모든 날짜 및 
//시간 (둘 다 표준 및 사용자 지정 형식 문자열) 
//및 시간 간격 (둘 다 표준 및 사용자 지정 형식 문자열), 모든 열거형 형식 열거형 형식, 및 GUIDs합니다. 
//또한 사용자 고유의 형식에 형식 문자열에 대 한 지원을 추가할 수 있습니다.
 
 
 
 
 
 
//{0:-15} 또는 //{0:15}  + 
//- 가 오면 글자가 왼쪽부터 배치된다
//+ 가 오면 글자가 오른쪽부터 배치된다
//간격을 제어합니다.
//결과 문자열에 삽입 되는 문자열의 너비를 정의할 수 있습니다 {0,12}, 
//문자열 12를 삽입 합니다. 이 경우 첫 번째 개체의 문자열 표현을 12 자 필드에 오른쪽 맞춤를입니다.
//(첫 번째 개체의 문자열 표현을 길이 12 자 이면 그러나 기본 필드 너비는 무시 됩니다 및 
//전체 문자열이 결과 문자열에 삽입 됩니다.)
 
//다음 예제에서는 정의 문자열을 보관할 6 자 필드 "Year" 및 일부 연도 문자열으로 15 자 필드는 문자열을 보관할 "채우기"와
//일부 인구 데이터입니다. 문자는 오른쪽 정렬 필드에 note 합니다.
 
int[] years = { 201320142015 };
int[] population = { 102563211059671148203 };
String s = String.Format("{0,6} {1,15}\n\n""Year""Population");
for(int index = 0; index < years.Length; index++)
   s += String.Format("{0,6} {1,15:N0}\n",
                      years[index], population[index]);
// Result:
//      Year      Population
//
//      2013       1,025,632
//      2014       1,105,967
//      2015       1,148,203
 
 
 
 
 
 
//맞춤을 제어합니다.
//기본적으로 문자열은 해당 필드 내에서 오른쪽 정렬 필드 너비를 지정 하는 경우입니다. 문자열 필드에서를 
//왼쪽에 맞추려면 앞에 음수 기호를 사용 하 여 필드 너비와 같은 {0,-12} 12 자로 오른쪽 정렬 필드를 정의 합니다.
//다음 예제에서는 왼쪽 맞춤 레이블과 데이터 한다는 점을 제외 하면 이전 쿼리와 비슷합니다.
 
int[] years = { 201320142015 };
int[] population = { 102563211059671148203 };
String s = String.Format("{0,-10} {1,-10}\n\n""Year""Population");
for(int index = 0; index < years.Length; index++)
   s += String.Format("{0,-10} {1,-10:N0}\n",
                      years[index], population[index]);
// Result:
//    Year       Population
//
//    2013       1,025,632
//    2014       1,105,967
//    2015       1,148,203
 
 
 
 
 
 
 




ref : https://msdn.microsoft.com/ko-kr/library/system.string.format(v=vs.110).aspx



반응형
반응형



using static System.Console;


C# 6.0 이후 버전 이후부터 위 구문을 사용하여 WriteLine 명령어를 간단하게 사용 할 수 잇다





다음 예제에서는 형식 이름을 지정할 필요 없이 using static 지시문을 사용하여 ConsoleMath 및 String 클래스의 정적 멤버를 사용 가능하게 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using static System.Console;
using static System.Math;
using static System.String;
 
class Program
{
   static void Main()
   {
      Write("Enter a circle's radius: ");
      var input = ReadLine();
      if (!IsNullOrEmpty(input) && double.TryParse(input, out var radius)) {
         var c = new Circle(radius);
         
         string s = "\nInformation about the circle:\n";
         s = s + Format("   Radius: {0:N2}\n", c.Radius);
         s = s + Format("   Diameter: {0:N2}\n", c.Diameter);
         s = s + Format("   Circumference: {0:N2}\n", c.Circumference);
         s = s + Format("   Area: {0:N2}\n", c.Area);
         WriteLine(s);
      }
      else {
         WriteLine("Invalid input...");
      }
   }
}
 
public class Circle
{
   public Circle(double radius)
   {
      Radius = radius;
   }
 
   public double Radius { get; set; }
 
   public double Diameter
   {
      get { return 2 * Radius; }
   }
 
   public double Circumference
   {
      get { return 2 * Radius * PI; }      
   }
 
   public double Area
   {
      get { return PI * Pow(Radius, 2); }
   }
}
// The example displays the following output:
//       Enter a circle's radius: 12.45
//       
//       Information about the circle:
//          Radius: 12.45
//          Diameter: 24.90
//          Circumference: 78.23
//          Area: 486.95





ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/using-static



반응형
반응형

int si = 3; Console.WriteLine$"{si}" ); //6.0 버전부터 $"{변수명}" 의 표기법으로 출력 가능하다

// This code example demonstrates the Console.WriteLine() method.
// Formatting for this example uses the "en-US" culture.

using System;
class Sample 
{
    enum Color {Yellow = 1, Blue, Green};
    static DateTime thisDate = DateTime.Now;

    public static void Main() 
    {
    Console.Clear();

// Format a negative integer or floating-point number in various ways.
    Console.WriteLine("Standard Numeric Format Specifiers");
    Console.WriteLine(
        "(C) Currency: . . . . . . . . {0:C}\n" +
        "(D) Decimal:. . . . . . . . . {0:D}\n" +
        "(E) Scientific: . . . . . . . {1:E}\n" +
        "(F) Fixed point:. . . . . . . {1:F}\n" +
        "(G) General:. . . . . . . . . {0:G}\n" +
        "    (default):. . . . . . . . {0} (default = 'G')\n" +
        "(N) Number: . . . . . . . . . {0:N}\n" +
        "(P) Percent:. . . . . . . . . {1:P}\n" +
        "(R) Round-trip: . . . . . . . {1:R}\n" +
        "(X) Hexadecimal:. . . . . . . {0:X}\n",
        -123, -123.45f); 

// Format the current date in various ways.
    Console.WriteLine("Standard DateTime Format Specifiers");
    Console.WriteLine(
        "(d) Short date: . . . . . . . {0:d}\n" +
        "(D) Long date:. . . . . . . . {0:D}\n" +
        "(t) Short time: . . . . . . . {0:t}\n" +
        "(T) Long time:. . . . . . . . {0:T}\n" +
        "(f) Full date/short time: . . {0:f}\n" +
        "(F) Full date/long time:. . . {0:F}\n" +
        "(g) General date/short time:. {0:g}\n" +
        "(G) General date/long time: . {0:G}\n" +
        "    (default):. . . . . . . . {0} (default = 'G')\n" +
        "(M) Month:. . . . . . . . . . {0:M}\n" +
        "(R) RFC1123:. . . . . . . . . {0:R}\n" +
        "(s) Sortable: . . . . . . . . {0:s}\n" +
        "(u) Universal sortable: . . . {0:u} (invariant)\n" +
        "(U) Universal full date/time: {0:U}\n" +
        "(Y) Year: . . . . . . . . . . {0:Y}\n", 
        thisDate);

// Format a Color enumeration value in various ways.
    Console.WriteLine("Standard Enumeration Format Specifiers");
    Console.WriteLine(
        "(G) General:. . . . . . . . . {0:G}\n" +
        "    (default):. . . . . . . . {0} (default = 'G')\n" +
        "(F) Flags:. . . . . . . . . . {0:F} (flags or integer)\n" +
        "(D) Decimal number: . . . . . {0:D}\n" +
        "(X) Hexadecimal:. . . . . . . {0:X}\n", 
        Color.Green);       
    }
}
/*
This code example produces the following results:

Standard Numeric Format Specifiers
(C) Currency: . . . . . . . . ($123.00)
(D) Decimal:. . . . . . . . . -123
(E) Scientific: . . . . . . . -1.234500E+002
(F) Fixed point:. . . . . . . -123.45
(G) General:. . . . . . . . . -123
    (default):. . . . . . . . -123 (default = 'G')
(N) Number: . . . . . . . . . -123.00
(P) Percent:. . . . . . . . . -12,345.00 %
(R) Round-trip: . . . . . . . -123.45
(X) Hexadecimal:. . . . . . . FFFFFF85

Standard DateTime Format Specifiers
(d) Short date: . . . . . . . 6/26/2004
(D) Long date:. . . . . . . . Saturday, June 26, 2004
(t) Short time: . . . . . . . 8:11 PM
(T) Long time:. . . . . . . . 8:11:04 PM
(f) Full date/short time: . . Saturday, June 26, 2004 8:11 PM
(F) Full date/long time:. . . Saturday, June 26, 2004 8:11:04 PM
(g) General date/short time:. 6/26/2004 8:11 PM
(G) General date/long time: . 6/26/2004 8:11:04 PM
    (default):. . . . . . . . 6/26/2004 8:11:04 PM (default = 'G')
(M) Month:. . . . . . . . . . June 26
(R) RFC1123:. . . . . . . . . Sat, 26 Jun 2004 20:11:04 GMT
(s) Sortable: . . . . . . . . 2004-06-26T20:11:04
(u) Universal sortable: . . . 2004-06-26 20:11:04Z (invariant)
(U) Universal full date/time: Sunday, June 27, 2004 3:11:04 AM
(Y) Year: . . . . . . . . . . June, 2004

Standard Enumeration Format Specifiers
(G) General:. . . . . . . . . Green
    (default):. . . . . . . . Green (default = 'G')
(F) Flags:. . . . . . . . . . Green (flags or integer)
(D) Decimal number: . . . . . 3
(X) Hexadecimal:. . . . . . . 00000003

*/


반응형
반응형

자동 완성(인텔리센스)


namespace 탭탭 을 두번 누르면 { } 가 자동 완성된다 

for 탭탭 하면 기본 for 구문이 만들어짐

svm 탭탭  하면

static void Main(string[] args)
    {
 
    }


이 구문이 자동 완성 되며

class 탭탭 의 경우도 

class MyClass
{
 
}

처럼 자동으로 만들어지며 커서거 MyClass 에 가 있게 되어 바로 클래스 명을 수정 할 수 있는 편의 기능을 제공한다 VS 에서..









\r 의 경우 커서를 제잎 앞으로 이동 시키는 명령어가 된다



 
"  " 사이에 개행을 했어도 @ 를 " 앞에 붙이면 여러 줄에 걸처 문자열을 적을 수 있다(단순 편리성 제공)
Console.WriteLine(@"s 
    df");



이스케이프 시퀀스



백슬래시(\) 뒤에 한 문자나 숫자 조합이 오는 문자 조합을 "이스케이프 시퀀스"라고 합니다. 줄 바꿈 문자, 작은따옴표, 또는 문자 상수의 다른 특정 문자를 나타내려면 이스케이프 시퀀스를 사용해야 합니다. 이스케이프 시퀀스는 단일 문자로 간주되므로 문자 상수로 유효합니다.

이스케이프 시퀀스는 일반적으로 터미널과 프린터의 캐리지 리턴 및 탭 이동과 같은 동작을 지정하는 데 사용됩니다. 또한 인쇄할 수 없는 문자 및 큰따옴표(")와 같이 일반적으로 특별한 의미를 가진 문자의 리터럴 표현을 제공하는 데 사용됩니다. 다음 표에서는 ANSI 이스케이프 시퀀스 및 나타내는 사항을 보여 줍니다.

앞에 백슬래시가 오는 물음표(\?)는 문자 시퀀스가 삼중자로 잘못 해석되는 경우 리터럴 물음표를 지정합니다. 자세한 내용은 삼중자를 참조하세요.

이스케이프 시퀀스

이스케이프 시퀀스표현
\a벨(경고)
\b백스페이스
\f폼 피드
\n줄 바꿈
\r캐리지 리턴
\t가로 탭
\v세로 탭
\'작은따옴표
\"큰따옴표
\\백슬래시
\?리터럴 물음표
\ ooo8진수 표기법의 ASCII 문자
\x hh16진수 표기법의 ASCII 문자
\x hhhh이 이스케이프 시퀀스가 와이드 문자 상수 또는 유니코드 문자열 리터럴에 사용되는 경우 16진수 표기법의 유니코드 문자입니다.

예를 들어 WCHAR f = L'\x4e00' 또는 WCHAR b[] = L"The Chinese character for one is \x4e00"로 이름을 지정할 수 있습니다.

Microsoft 전용

표에 없는 문자 앞에 백슬래시가 오는 경우 컴파일러는 정의되지 않은 문자를 문자 자체로 처리합니다. 예를 들어 \c는 c로 처리됩니다.

Microsoft 전용 종료

이스케이프 시퀀스를 사용하여 디스플레이 장치에 비그래픽 제어 문자를 보낼 수 있습니다. 예를 들어 ESC 문자(\033)는 터미널 또는 프린터에 대한 제어 명령의 첫 문자로 자주 사용됩니다. 일부 이스케이프 시퀀스는 장치별로 적용됩니다. 예를 들어 세로 탭 및 용지 공급 이스케이프 시퀀스(\v 및 \f)는 화면 출력에는 영향을 주지 않고 해당 프린터 작업을 수행합니다.

백슬래시(\)를 연속 문자로 사용할 수도 있습니다. 줄 바꿈 문자(Return 키 누름과 같음)가 백슬래시 바로 뒤에 오는 경우 컴파일러는 백슬래시와 줄 바꿈 문자를 무시하고 다음 줄을 앞 줄의 일부로 처리합니다. 한 줄보다 긴 전처리기 정의에 주로 유용합니다. 예:



1
2
#define assert(exp) \  
( (exp) ? (void) 0:_assert( #exp, __FILE__, __LINE__ ) )  



ref : https://msdn.microsoft.com/ko-kr/library/h21280bw.aspx










반응형
반응형

1. Func? Action?


프로그램을 작성하던 중에 갑자기 무명 메소드가 필요해졌다고 생각해 보자.


무명 메소드를 사용하기 위해서는 이를 참조할 수 있는 델리게이트 변수가 있어야 하며,


또한 델리게이트 변수를 생성하기에 앞서 델리게이트 타입을 선언해야 한다.


그러면 각기 다른 타입의 무명 메소드를 여러개 만들 때는 어떻게 해야할까?


당연히 무명 메소드마다 그 타입에 맞는 델리게이트 타입과 변수를 따로 따로 선언해야 할 것이다.


이는 매우 비효율적인 작업이기 때문에 C#에서는 Func과 Action이라는 델리게이트를 제공한다.



Func와 Action은 미리 선언된 델리게이트 변수로써 별도의 선언없이 사용가능하다.


Func는 반환값이 있는 메소드를 참조하는 델리게이트 변수이고,


Action은 반환값이 없는 메소드를 참조하는 델리게이트 변수이다.




2. Func 델리게이트


.NET Framework에는 총 17가지의 Func 델리게이트가 준비되어 있다.


즉, 매개변수가 없는 메소드부터 매개변수가 16개인 메소드까지 


총 17개의 메소드를 참조 가능하다는 말이다. (무명 메소드 뿐만 아니라 일반 메소드도 참조 가능)


이정도면 특별한 경우가 아니고서야 별도의 델리게이트를 만들어 쓸 필요가 없겠다.


Func 델리게이트 변수를 선언하는 방법은 다음과 같다.




매개변수와 반환값을 구분하기 위해 int형과 float형으로 나누었다.


보시다시피 매개변수는 앞에서 지정하고, 반환값은 맨 뒤에 지정하는 것을 확인할 수 있다.

 

( Func는 반환값을 가진 메소드를 참조하는 델리게이트이기 때문에,


반환형을 반드시 지정해주어야 한다. )


위와 같이 Func 델리게이트로 메소드를 참조하면 전처럼 델리게이트 타입을 선언하는 과정이 


불필요해지므로 아주 간결하게 코드를 작성할 수 있다.



그럼 이제 다음 예제를 작성해보자.







3. Action 델리게이트


Action 델리게이트는 Func와 똑같다. 다만 참조하는 메소드의 반환값이 없을 뿐이다.




반환값이 없는것 빼고는 Func랑 똑같아서 딱히 설명이 필요 없겠다.


바로 아래 예제를 작성해보자.




ref : http://mrw0119.tistory.com/23







이벤트가 생겨난 이유는 속성이 생긴 이유와 비슷하다데이터 접근에 한 단계를 더 추가하여 캡슐화를 강화한다는 것에 있다다른 코드가 클래스의 필드 값을 최소한의 검증 작업도 없이 직접 수정하는 것이 바람직하지 않듯이 클래스 외부의 다른 코드가 특정 이벤트의 핸들러를 변경/호출 하는 것도 바람직하지 않다.  실제로 이벤트를 사용하면 컴파일러는 이 선언을 private 델리게이트 Type Filed로 변환하고 Add/Remove 기본 메서드를 구현해준다클래스 내부에서는 이것이 필드로 보이고 외부에서는 이벤트로 보이는 것이다.

 

 

 

 

실습을 통한 확인 

 

 아래는 이를 분석하는 간단한 코드를 작성하고 이에 대한 역어셈블 및 IL코드를 통해서 확인해보자. 

 

이벤트를 사용하는 클래스를 이용하여 이벤트 핸들러를 등록하고 다른 클래스에서 호출하는 예

 

using System;

 

namespace EventDasm

{

    delegate void EventDelegate();

 

class MyEventClass

    {

        public event EventDelegate Event;

 

        public void EventHandler()

        {

            Event();

        }

    }

 

 

    class Program

    {

        static void Main(string[] args)

        {

            MyEventClass EventInstance = new MyEventClass();

            EventInstance.Event += new EventDelegate(EventInstance_Event);

 

            EventInstance.EventHandler();

        }

 

        static void EventInstance_Event()

        {

            Console.WriteLine("이벤트 발생");

        }

    }

}

 

다음은 위 코드의 MyEventClass에 대한 역어셈블 결과 및 IL코드이다.

Disassemble

IL코드

보이는 것처럼 CLR에 의하여 자동적으로 private 델리게이트 타입 필드가 생성되고이에 대한add/remove메서드가 생성된 것을 확인할 수 있다.

 

 

지금까지 내용을 한 마디로 정리하면 다음과 같다

                                    “Event Delegate를 캡슐화 시킨 것이다.”





ref : https://silent1002.blog.me/10086120655

반응형
반응형

방법: 숫자 앞에 0으로 채우기

"D" 표준 숫자 서식 문자열과 함께 전체 자릿수 지정자를 사용하여 앞에 오는 0을 정수에 추가할 수 있습니다. 사용자 지정 숫자 서식 문자열을 사용하여 정수와 부동 소수점 숫자 둘 다에 앞에 오는 0을 추가할 수 있습니다. 이 항목에서는 두 개의 메서드를 사용하여 앞에 오는 0으로 숫자를 채우는 방법을 보여 줍니다.

앞에 오는 0으로 특정 길이까지 정수를 채우려면

  1. 표시할 정수 값의 최소 자릿수를 결정합니다. 이 숫자에 원하는 선행 자릿수를 포함합니다.

  2. 정수를 10진수 값으로 표시할지 아니면 16진수 값으로 표시할지를 결정합니다.

    • 호출 된 정수를 10 진수 값으로 표시 하려면 해당 ToString(String) 메서드와 패스 문자열 "Dn"의 값으로는 format 매개 변수를 여기서 n 문자열의 최소 길이 나타냅니다.

    • 호출 된 정수를 16 진수 값으로 표시 하려면 해당 ToString(String) 메서드와 전달 된 문자열 "Xn"의 값으로는 format 매개 변수를 여기서 n 문자열의 최소 길이 나타냅니다.

    메서드, 형식 문자열와 같은 사용할 수도 Format 또는 WriteLine를 사용 하 여 합성 서식 지정합니다.

다음 예제에서는 서식이 지정된 숫자의 전체 길이가 8자 이상이 되도록 앞에 오는 0으로 여러 정수 값의 서식을 지정합니다.

C#
byte byteValue = 254;
short shortValue = 10342;
int intValue = 1023983;
long lngValue = 6985321;               
ulong ulngValue = UInt64.MaxValue;

// Display integer values by calling the ToString method.
Console.WriteLine("{0,22} {1,22}", byteValue.ToString("D8"), byteValue.ToString("X8"));
Console.WriteLine("{0,22} {1,22}", shortValue.ToString("D8"), shortValue.ToString("X8"));
Console.WriteLine("{0,22} {1,22}", intValue.ToString("D8"), intValue.ToString("X8"));
Console.WriteLine("{0,22} {1,22}", lngValue.ToString("D8"), lngValue.ToString("X8"));
Console.WriteLine("{0,22} {1,22}", ulngValue.ToString("D8"), ulngValue.ToString("X8"));
Console.WriteLine();

// Display the same integer values by using composite formatting.
Console.WriteLine("{0,22:D8} {0,22:X8}", byteValue);
Console.WriteLine("{0,22:D8} {0,22:X8}", shortValue);
Console.WriteLine("{0,22:D8} {0,22:X8}", intValue);
Console.WriteLine("{0,22:D8} {0,22:X8}", lngValue);
Console.WriteLine("{0,22:D8} {0,22:X8}", ulngValue);
// The example displays the following output:
//                     00000254               000000FE
//                     00010342               00002866
//                     01023983               000F9FEF
//                     06985321               006A9669
//         18446744073709551615       FFFFFFFFFFFFFFFF
//       
//                     00000254               000000FE
//                     00010342               00002866
//                     01023983               000F9FEF
//                     06985321               006A9669
//         18446744073709551615       FFFFFFFFFFFFFFFF
//         18446744073709551615       FFFFFFFFFFFFFFFF

특정 수의 앞에 오는 0으로 정수를 채우려면

  1. 정수 값을 표시하는 데 사용할 앞에 오는 0의 수를 결정합니다.

  2. 정수를 10진수 값으로 표시할지 아니면 16진수 값으로 표시할지를 결정합니다. 10진수 값으로 서식을 지정하려면 "D" 표준 서식 지정자를 사용해야 하고, 16진수 값으로 서식을 지정하려면 "X" 표준 서식 지정자를 사용해야 합니다.

  3. 정수 값의 ToString("D").Length 또는 ToString("X").Length 메서드를 호출하여 채워지지 않은 숫자 문자열의 길이를 확인합니다.

  4. 서식이 지정된 문자열에 포함할 앞에 오는 0의 수를 채워지지 않은 숫자 문자열의 길이에 추가합니다. 그러면 채워진 문자열의 전체 길이가 정의됩니다.

  5. 정수 값의 호출 ToString(String) 메서드와 패스 문자열 "Dn" 10 진수 문자열 및 "Xn" 16 진수 문자열에 대 한 여기서 n 채워진된 문자열의 총 길이 나타냅니다. 사용할 수도 있습니다는 "Dn" 또는 "Xn" 복합 형식을 지 원하는 메서드의 문자열의 형식을 지정 합니다.

다음 예제에서는 5개의 앞에 오는 0으로 정수 값을 채웁니다.

C#
int value = 160934;
int decimalLength = value.ToString("D").Length + 5;
int hexLength = value.ToString("X").Length + 5;
Console.WriteLine(value.ToString("D" + decimalLength.ToString()));
Console.WriteLine(value.ToString("X" + hexLength.ToString()));
// The example displays the following output:
//       00000160934
//       00000274A6      

앞에 오는 0으로 특정 길이까지 숫자 값을 채우려면

  1. 숫자의 문자열 표현에서 정수 부분을 표시하는 데 사용할 자릿수를 결정합니다. 이 숫자의 전체 자릿수에 원하는 수의 앞에 오는 0을 포함합니다.

  2. 0 자리 표시자("0")를 사용하여 0의 최소 수를 나타내는 사용자 지정 숫자 서식 문자열을 정의합니다.

  3. 숫자의 ToString(String) 메서드를 호출하여 사용자 지정 서식 문자열에 전달합니다. 또한 합성 서식 지정을 지원하는 메서드에 사용자 지정 서식 문자열을 사용할 수 있습니다.

다음 예제에서는 서식이 지정된 숫자에서 정수 부분의 전체 길이가 8자 이상이 되도록 앞에 오는 0으로 여러 숫자 값의 서식을 지정합니다.

C#
string fmt = "00000000.##";
int intValue = 1053240;
decimal decValue = 103932.52m;
float sngValue = 1549230.10873992f;
double dblValue = 9034521202.93217412;

// Display the numbers using the ToString method.
Console.WriteLine(intValue.ToString(fmt));
Console.WriteLine(decValue.ToString(fmt));           
Console.WriteLine(sngValue.ToString(fmt));
Console.WriteLine(dblValue.ToString(fmt));           
Console.WriteLine();

// Display the numbers using composite formatting.
string formatString = " {0,15:" + fmt + "}";
Console.WriteLine(formatString, intValue);      
Console.WriteLine(formatString, decValue);      
Console.WriteLine(formatString, sngValue);      
Console.WriteLine(formatString, dblValue);      
// The example displays the following output:
//       01053240
//       00103932.52
//       01549230
//       9034521202.93
//       
//               01053240
//            00103932.52
//               01549230
//          9034521202.93      

특정 수의 앞에 오는 0으로 숫자 값을 채우려면

  1. 숫자 값을 표시하는 데 사용할 앞에 오는 0의 수를 결정합니다.

  2. 채워지지 않은 숫자 문자열에서 정수 부분의 자릿수를 확인합니다. 이렇게 하려면 다음을 수행합니다.

    1. 숫자의 문자열 표현에 소수점 기호가 포함되어 있는지 확인합니다.

    2. 소수점 기호가 포함되어 있으면 정수 부분에 있는 문자 수를 확인합니다.

      또는

      소수점 기호가 포함되어 있지 않으면 문자열의 길이를 확인합니다.

  3. 문자열에 표시할 각 앞에 오는 0에 대해 0 자리 표시자("0")를 사용하고 0 자리 표시자 또는 10진수 자리 표시자("#")를 사용하여 기본 문자열에 있는 각 자릿수를 나타내는 사용자 지정 서식 문자열을 만듭니다.

  4. 사용자 지정 서식 문자열을 숫자의 ToString(String) 메서드에 대한 매개 변수 또는 합성 서식 지정을 지원하는 메서드에 대한 매개 변수로 제공합니다.

다음 예제에서는 5개의 앞에 오는 0으로 두 개의 Double 값을 채웁니다.

C#
double[] dblValues = { 9034521202.93217412, 9034521202 };
foreach (double dblValue in dblValues)
{
   string decSeparator = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
   string fmt, formatString;
   
   if (dblValue.ToString().Contains(decSeparator))
   {
      int digits = dblValue.ToString().IndexOf(decSeparator);
      fmt = new String('0', 5) + new String('#', digits) + ".##";
   }
   else
   {
      fmt = new String('0', dblValue.ToString().Length);   
   }
   formatString = "{0,20:" + fmt + "}";

   Console.WriteLine(dblValue.ToString(fmt));
   Console.WriteLine(formatString, dblValue);
}
// The example displays the following output:
//       000009034521202.93
//         000009034521202.93
//       9034521202
//                 9034521202            


반응형
반응형
using System;

public class Example
{
   public static void Main()
   {
      string[] values = { "+13230", "-0", "1,390,146", "$190,235,421,127",
                          "0xFA1B", "163042", "-10", "007", "2147483647", 
                          "2147483648", "16e07", "134985.0", "-12034",
                          "-2147483648", "-2147483649" };
      foreach (string value in values)
      {
         try {
            int number = Int32.Parse(value); 
            Console.WriteLine("{0} --> {1}", value, number);
         }
         catch (FormatException) {
            Console.WriteLine("{0}: Bad Format", value);
         }   
         catch (OverflowException) {
            Console.WriteLine("{0}: Overflow", value);   
         }  
      }
   }
}
// The example displays the following output:
//       +13230 --> 13230
//       -0 --> 0
//       1,390,146: Bad Format
//       $190,235,421,127: Bad Format
//       0xFA1B: Bad Format
//       163042 --> 163042
//       -10 --> -10
//       007 --> 7
//       2147483647 --> 2147483647
//       2147483648: Overflow
//       16e07: Bad Format
//       134985.0: Bad Format
//       -12034 --> -12034
//       -2147483648 --> -2147483648
//       -2147483649: Overflow      


반응형
반응형


IEnumerable 에서 다뤄지는 요소들이 꼭 배열일 필요는 없다, 상황에 맞는 구조를 사용하면 됨



IEnumerator모든 제네릭이 아닌 열거자에 대 한 기본 인터페이스입니다.

이 인터페이스의 제네릭 버전에 대 한 참조 IEnumerator<T>합니다.

@FSHO1@C# 언어의 foreach 문(Visual Basic의 경우 for each)은 열거자의 복잡성을 숨깁니다. 따라서 사용 하 여 foreach 열거자를 직접 조작 하는 대신 것이 좋습니다.

열거자를 사용하여 컬렉션의 데이터를 읽을 수는 있지만 내부 컬렉션을 수정할 수는 없습니다.

Reset 메서드는 COM 상호 운용성을 위해 제공 되며 완벽 하 게 구현 하지 않아도; 구현자 대신 throw 할 수는 NotSupportedException합니다.

처음에 열거자는 컬렉션의 첫 번째 요소 앞에 배치됩니다. 호출 해야 합니다는 MoveNext 하 여 열거자의 값을 읽기 전에 컬렉션의 첫 번째 요소로 메서드 Current, 그렇지 않으면 Current 정의 되지 않습니다.

Current에서는 MoveNext 또는 Reset이 호출될 때까지 동일한 개체를 반환합니다. MoveNext는 Current를 다음 요소로 설정합니다.

경우 MoveNext 전달 컬렉션의 마지막 요소 뒤에 열거자는 컬렉션의 끝에 배치 되 고 MoveNext 반환 false합니다. 열거자가 있는 경우이 위치에 대 한 후속 호출에서 MoveNext 반환할 수도 false합니다. 마지막으로 호출 하는 경우 MoveNext 반환 false호출, Current 예외를 throw 합니다.

설정 하려면 Current 다시 컬렉션의 첫 번째 요소를 호출할 수 있습니다 Reset구현 되는 경우, 다음 MoveNext합니다. 경우 Reset 는 구현 하지 않은 만들어야 새 열거자 인스턴스를 컬렉션의 첫 번째 요소를 반환 합니다.

열거자는 컬렉션이 변경되지 않은 상태로 유지되는 한 유효한 상태를 유지합니다. 변경, 추가 하는 등 컬렉션을 수정 하거나 요소를 삭제 하면 열거자가 더 유효 하지 않으며을 다음에 호출할 MoveNext 또는 Reset throw는 InvalidOperationException합니다. 사이 컬렉션이 수정 되는 경우 MoveNext 및 CurrentCurrent 열거자가 이미 무효로 되 었 하는 경우에 설정 하는 요소를 반환 합니다.

열거자는 컬렉션에 배타적으로 액세스하지 못하므로 컬렉션을 열거하는 것은 본질적으로 스레드로부터 안전한 프로시저가 아닙니다. 컬렉션이 동기화되어 있을 때 다른 스레드에서 해당 컬렉션을 수정할 수 있으므로 이렇게 되면 열거자에서 예외가 throw됩니다. 열거하는 동안 스레드로부터 안전을 보장하려면 전체 열거를 수행하는 동안 컬렉션을 잠그거나 다른 스레드에서 변경된 내용으로 인해 발생한 예외를 catch하면 됩니다.



다음 코드 예제에서는의 구현을 설명는 IEnumerable 및 IEnumerator 사용자 지정 컬렉션에 대 한 인터페이스입니다. 이 예제에서는 이러한 인터페이스의 멤버는 명시적으로 호출 되지 않지만의 사용을 지원 하도록 구현 됩니다 foreach (for each Visual basic에서)는 컬렉션을 반복 합니다.



using System;
using System.Collections;

// Simple business object.
public class Person
{
    public Person(string fName, string lName)
    {
        this.firstName = fName;
        this.lastName = lName;
    }

    public string firstName;
    public string lastName;
}

// Collection of Person objects. This class
// implements IEnumerable so that it can be used
// with ForEach syntax.
public class People : IEnumerable
{
    private Person[] _people;
    public People(Person[] pArray)
    {
        _people = new Person[pArray.Length];

        for (int i = 0; i < pArray.Length; i++)
        {
            _people[i] = pArray[i];
        }
    }

// Implementation for the GetEnumerator method.
    IEnumerator IEnumerable.GetEnumerator()
    {
       return (IEnumerator) GetEnumerator();
    }

    public PeopleEnum GetEnumerator()
    {
        return new PeopleEnum(_people);
    }
}

// When you implement IEnumerable, you must also implement IEnumerator.
public class PeopleEnum : IEnumerator
{
    public Person[] _people;

    // Enumerators are positioned before the first element
    // until the first MoveNext() call.
    int position = -1;

    public PeopleEnum(Person[] list)
    {
        _people = list;
    }

    public bool MoveNext()
    {
        position++;
        return (position < _people.Length);
    }

    public void Reset()
    {
        position = -1;
    }

    object IEnumerator.Current
    {
        get
        {
            return Current;
        }
    }

    public Person Current
    {
        get
        {
            try
            {
                return _people[position];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}

class App
{
    static void Main()
    {
        Person[] peopleArray = new Person[3]
        {
            new Person("John", "Smith"),
            new Person("Jim", "Johnson"),
            new Person("Sue", "Rabon"),
        };

        People peopleList = new People(peopleArray);
        foreach (Person p in peopleList)
            Console.WriteLine(p.firstName + " " + p.lastName);

    }
}

/* This code produces output similar to the following:
 *
 * John Smith
 * Jim Johnson
 * Sue Rabon
 *
 */



ref : https://msdn.microsoft.com/ko-kr/library/system.collections.ienumerator(v=vs.110).aspx


반응형
반응형



C# 3.0 이상에서는 속성 접근자에 추가적인 논리가 필요하지 않을 경우 자동 구현 속성을 통해 속성 선언이 더 간결해집니다. 이를 통해 클라이언트 코드에서 개체를 만들 수도 있습니다. 다음 예제와 같이 속성을 선언할 때 컴파일러는
속성의 get 및 set 접근자를 통해서만 액세스할 수 있는 전용 익명 지원 필드를 만듭니다.

예제

다음 예제에서는 일부 자동 구현 속성이 있는 간단한 클래스를 보여 줍니다.

C#

// This class is mutable. Its data can be modified from
// outside the class.
class Customer
{
    // Auto-Impl Properties for trivial get and set
    public double TotalPurchases { get; set; }
    public string Name { get; set; }
    public int CustomerID { get; set; }

    // Constructor
    public Customer(double purchases, string name, int ID)
    {
        TotalPurchases = purchases;
        Name = name;
        CustomerID = ID;
    }
    // Methods
    public string GetContactInfo() {return "ContactInfo";}
    public string GetTransactionHistory() {return "History";}

    // .. Additional methods, events, etc.
}

class Program
{
    static void Main()
    {
        // Intialize a new object.
        Customer cust1 = new Customer ( 4987.63, "Northwind",90108 );

        //Modify a property
        cust1.TotalPurchases += 499.99;
    }
}

C# 6 이상 버전에서는 필드와 유사하게 자동 구현 속성을 초기화할 수 있습니다.

C#
public string FirstName { get; set; } = "Jane";  

앞의 예제에 표시된 클래스는 변경할 수 있습니다. 클라이언트 코드에서는 개체가 만들어진 후 개체의 값을 변경할 수 있습니다. 데이터 및 중요 동작(메서드)을 포함하는 복잡한 클래스에는 공용 속성을 포함해야 할 수 있습니다. 그러나 값 집합(데이터)만 캡슐화하고 동작이 적거나 없는 작은 클래스나 구조체의 경우 set 접근자를 private로 선언하거나(소비자에 대한 변경 불가능) get 접근자만 선언하여(생성자를 제외한 모든 위치에서 변경 불가능) 개체를 변경 불가능으로 설정해야 합니다. 자세한 내용은 방법: 자동으로 구현된 속성을 사용하여 간단한 클래스 구현을 참조하세요.


특성은 자동 구현 속성에서 허용되지만, 소스 코드에서 액세스할 수 없으므로 지원 필드에서는 분명히 허용되지 않습니다. 속성의 지원 필드에서 특성을 사용해야 할 경우 일반 속성만 만듭니다.


https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties



반응형
반응형
Nullable 타입의 도입 

C#에서 정수, 부동자릿수, 구조체 등의 Value Type은 NULL을 가질 수 없다. 예를 들어, 정수 int i 가 있을 때 변수 i에는 null을 할당할 수 없으며, 따라서 변수 i는 어떤 값이 할당되지 않은 상태 (missing value)를 가질 수 없다.
만약 정수형 변수 i에 값이 설정되지 않은 상태를 할당하려면, 개발자는 2가지 방법을 사용할 수 있을 것이다. 즉, (1)프로그램에서 사용될 것 같지 않은 특정 값을 추정하여 할당하던지 (예를 들어, int i = int.MaxValue;) (2) 아니면 또 하나의 변수를 두어 변수 i가 missing임을 나타내게 할 수 있다 (예를 들어, bool iHasValue = false;). 이 두번째 방식이 Nullable의 기본 아이디어이다.

C# 에서는 Value Type에도 null을 할당할 수 있는 Nullable 타입을 지원한다. Nullable 타입은 Value 값을 갖고 있으면서 NULL 상태를 체크할 수 있는 기능(HasValue)을 함께 가지고 있는 struct 이다. 따라서 Nullable 타입은 struct(구조체)이므로 Value Type이다.

C#에서 int? 와 같이 해당 Value Type 뒤에 물음표를 붙이면, 해당 정수형 타입이 Nullable 정수형 타입임을 의미한다. 즉, 이 변수에는 NULL을 할당할 수 있다. C#의 이러한 특별한 문법은 .NET의 Nullable<T> 구조체로 컴파일시 변환된다. 즉, int?는 Nullable<int>와 동일하다. 





Nullable<T> 타입 

C#에서 int?, bool?, DateTime? 와 같은 T? 의 표현은 .NET의 Nullable<T>와 같은 표현이며, Nullable<T> 구조체는 값을 가지고 있는지를 체크하는 (즉, missing value가 아닌지를 체크하는) HasValue 속성과 실제 값을 나타내는 Value 속성을 가지고 있다. Nullable 구조체는 타입 캐스팅을 통한 변환이나 암묵적 변환을 통해 (Non-nullable) Value 타입으로 변환된다. 당연한 얘기지만, Value 타입이 아닌 레퍼런스 타입은 Nullable을 쓸 필요가 없는데, 그것은 모든 레퍼런스 타입은 이미 NULL을 허용하기 때문이다.
Nullable 타입이 실무에서 흔히 사용되는 케이스는 DB와 연동되는 Data Layer 클래스들을 들 수 있는데, 예를 들어 SQL 서버 테이블에서 NULL을 허용하는 숫자, 날짜, bool등의 컬럼이 있다면, 이 컬럼 타입은 Nullable 타입으로 변환되어 테이블의 NULL 속성을 표현하게 된다. 아래 예제는 다양한 종류의 Nullable 파라미터를 받아들여 HasValue로 NULL 값을 미리 체크한 후, .Value 속성을 써서 해당 타입의 실제 값을 사용하고 있다.

Nullable 타입과 연관되어 자주 사용되는 C#의 ?? 연산자는 ?? 앞의 파라미터가 NULL인 경우 연산자 뒤의 값을 할당할 때 사용한다. 


예제

double _Sum = 0;
DateTime _Time;
bool? _Selected;

public void CheckInput(int? i, double? d, DateTime? time, bool? selected)
{
    if (i.HasValue && d.HasValue)
        this._Sum = (double)i.Value + (double)d.Value;

    // time값이 있는 체크.
    if (!time.HasValue)
        throw new ArgumentException();
    else
        this._Time = time.Value;

    // 만약 selected가 NULL이면 false를 할당
    this._Selected = selected ?? false;
}



Nullable 정적 클래스 

.NET Framework에 있는 정적(static) 클래스 System.Nullable 은 두개의 Nullable 객체를 비교하거나 (Compare(), Equals() 메서드), 특정 Nullable 타입이 어떤 Value 타입에 기반을 두고 있는지 알아내는 (GetUnderlyingType() 메서드) 기능을 제공하고 있다. 이 정적 클래스는 Nullable<T> 타입을 위한 몇 가지 편리한 정적 메서드들을 제공한다. 

예제

void NullableTest()
{
    int? a = null;
    int? b = 0;            
    int result = Nullable.Compare<int>(a, b);
    Console.WriteLine(result); //결과 -1

    double? c = 0.01;
    double? d = 0.0100;
    bool result2 = Nullable.Equals<double>(c, d);
    Console.WriteLine(result2); //결과 true
}



http://www.csharpstudy.com/CSharp/CSharp-nullable.aspx



반응형
반응형


객체 초기화


새 오브젝트를 생성하면 내부의 속성 중 하나 이상에 값을 할당해야 합니다.

C# 3.0 이후에는 가독성 향상과 코드 단축을 위해 개체 자체의 초기화가 가능해졌습니다.


1
2
3
Customer c = new Customer();
c.Name = "James";
c.Address = "204 Lime Street";
cs


이와 같은 소스를 한 줄로 압축할 수 있습니다.


1
2
3
4
5
Customer c = new Customer
{
    Name="James",
    Address = "204 Lime Street"
};
cs




The using statement


자주 글꼴, 파일 핸들, 네트워크 리소스 등을 위해 시스템 자원을 사용합니다.



이런 리소스 등을 사용할 때 (Resource, You use it, dispose - 리소스, 할당 후 사용과 해제)란 중요한 점이 있지만, 메모리나 낭비되는 리소스들을 위한 Dispose 작업은 다들 잊어버립니다.

이런 리소스 등을 사용할 때 (Resource, You use it, dispose - 리소스, 할당 후 사용과 해제)란 중요한 점이 있지만, 메모리나 낭비되는 리소스들을 위한 Dispose 작업은 다들 잊어버립니다.


1
2
3
4
5
6
7
8
9
10
// 1. Allocation of the object
Font font1 = new Font("Arial"10.0f);
 
try{
    // 2. The bit where we use the resource
}finally{
    // 3. Disposal of the object
     if (font1 != null)
            ((IDisposable)font1).Dispose();
}
cs


그래서 Using 문을 사용해 코드를 축약합니다.


1
2
3
4
5
6
// Allocate the resource
using(Font font1 = new Font("Arial"10.0f))
{
      // The bit where we use the resource
}
      // Disposal is automatic
cs


using문은 실제 자원을 할당하고 관리하는 .NET 개체인데, "IDisposable" 인터페이스를 구현해 리소스 관리가 가능해 위와 같이 선언만 해놓으면 저절로 자원 관리가 됩니다.





Nullable objects


변수는 값을 가지고 있어야 하고, 비어있으면 안 됩니다.

때에 따라 비어야 할 때도 있고, 정의되지 않았을 경우 null을 할당하는 것이 편하기도 하며, .NET 2.0에서부터 Nullable을 도입했는데, 사용 예는 아래와 같습니다.


1
2
Nullable<int> x = null;
int? x = null;
cs


변수를 정의한 다음 ?를 넣고, 타입은 Nullable로 감싸서 사용합니다.



int? 자세한 설명 : http://www.csharpstudy.com/CSharp/CSharp-nullable.aspx



Automatic Properties


속성은 일반적으로 Getter과 Setter로 외부에 노출이 되고, 이를 이용해 값들을 할당합니다.


1
2
3
4
5
6
7
8
9
public class Person
{
    private string _firstName;
    public string FirstName;
    {
        get { return _firstName; }
        set { _firstName = value; }
    }
}
cs


C# 3.0에서부터 자동 속성이 추가되어, 아래처럼 사용할 수 있습니다.


1
2
3
4
5
6
7
8
public class Person
{
    public string Firstname 
    {
        get;
        set;
    }
}
cs



C#의 컴파일러는 자동으로 백업되는 변수를 생성, 올바른 설정, 속성 설정 등을 수행하기 때문에, Public 클래스 대신에 String 변수를 생성할 수 있습니다.

C# 6 이상 버전에서는 필드와 유사하게 자동 구현 속성을 초기화할 수 있습니다.

C#
public string FirstName { get; set; } = "Jane";  


참고 : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties






타입 유추


일반적으로 C#에선 아래와 같이 정의를 합니다.


1
string MyString = “Hello World”;
cs


=의 우측에 하나의 데이터 타입(string)을 적어 선언하는 건 너무나 일반적입니다.


근데, 이런 작업을 컴파일러가 대신할 순 없을까요?


1
var MyString = “Hello World”;
cs


바로 위의 코드 또한 "MyString"라는 문자열 변수를 생성합니다. 이런 일반적인 상황에서 유추(inference)를 통해 성능이 향상되진 않습니다.


컴파일 시, 어떤 작업 과정이든 데이터 타입에 대해선 먼저 생각하진 않습니다. 아래의 예를 통해 유추에 대해 알아볼 수 있습니다.


1
2
3
4
var SeniorStaff = Employees.Where(s => s.Age > 35);
 
foreach(var Member in SeniorStaff)
    Console.WriteLine("Name: {0} Age: {1}",Member.Name,Member.Age);
cs





람다 표현식(Lambda)


코드를 읽기에 난해할 수 있다는 단점이 있으나 내부적으로 구동하는 데 있어선 아주 좋은 방법입니다.


1
Func mySeniorStaffFilter = delegate(int a) { return a > 35; };
cs


위의 코드에선 직원의 수가 35보다 많다면 True를 반환합니다. 람다 표현 식으로는 좀 더 간결하고 (여기서는)읽기 쉽게 같은 의미를 표현할 수 있습니다.


1
Func mySeniorStaffFilter = a => a > 35;
cs


델리게이트를 이용하면 조금 더 코드를 멋지게 꾸밀 수도 있습니다.


1
var SeniorStaff = Employees.Where(s => s.Age > 35);
cs


string.IsNullOrEmpty


문자열이 비었는지 확인하려면 string.IsNullOrEmpty 함수를 사용해서 반환 값을 확인하세요.


1
2
3
4
if (String.IsNullOrEmpty(s) == true)
    return "is null or empty";
else
     return String.Format("(\"{0}\") is not null or empty", s);
cs


문자열의 대소문자 구분


때로는 Case(형식, 형태 등 변수의 속성)를 무시하는 문자열 비교 방법이 필요합니다. 일반적, 또는 전통적으로 문자열 비교 시 전체를 대문자나 소문자로 변환한 후 비교를 합니다.


1
str1.ToLower() == str2.ToLower()
cs


그렇지만 반복적으로 이를 이용하다 보면, 퍼포먼스 병목 현상이 벌어지기도 합니다. 대신에, String.Compare() 함수를 사용하면 프로그램의 수행 속도를 향상할 수 있습니다.


두 개의 문자열을 비교하면서 단순한 Case들은 무시하게 됩니다.


1
string.Compare(str1, str2, true== 0 //Ignoring cases
cs


0 이 반환된다면 두 문자열은 서로 같다는 뜻입니다.




ArrayList를 List<>로 교체하기


ArrayList는 여러 종류의 개체들을 다루기에 좋습니다.


그렇지만, ArrayList에 삽입되는 개체(변수)가 같은 타입이라면, 굳이 ArrayList를 고집할 필요 없이 List<>로 교체해서 성능을 향상할 필요가 있습니다.


1
2
3
4
ArrayList intList = new ArrayList();
intList.add(10);
 
return (int)intList[0+ 20;
cs


예를 들어, 이런 소스 코드를, 입력 목록의 변수 유형만 변경해 줍니다.


1
2
3
4
List<int> intList = new List<int>();
intList.add(10)
 
return intList[0+ 20;
cs


변수 타입을 별도로 캐스트 해줄 필요가 없어집니다. 성능 향상을 꾀할 수 있는 부분은 Integer와 같은 기본 데이터 타입들입니다.



+ ArrayList의 경우 Object 에 의한 참조를 사용하는 방식임으로 암시적 박싱이 일어나게 됨으로 성능상 느리다




&&와 || 사용하기


문장을 빌드할 땐 간단하게, &&, ||를 사용해 보세요(Visual Basic에서는 AndAlso, OrElse). 코드가 적어질 수 있고, 이 적은 코드는 향상된 성능뿐만 아니라 런타임 오류를 방지할 수도 있습니다.


아래는 간단한 예입니다.


1
if (object1 != null && object1.runMethod())
cs


object1은 NULL일 경우 object1.runMethod()가 실행되지 않습니다.


언제 StringBuilder를 사용해야 할까요?


StringBuilder 객체는 일반 문자열 함수보다 더 빠른 문자열 처리 속도를 보유하고 있습니다.

StringBuilder는 기다란 문자열을 처리하는데 아주 좋은 클래스이며, 문자열로 처리할 수 있는 부분을 StringBuilder로 대체하면 C# 소스 코드가 더 적은 리소스를 사용하고, 가독성도 높아질 수 있습니다.


문자열과 StringBuilder 객체를 효율적으로 사용함으로써 소스 코드를 최적화할 수 있습니다.


똑똑한 Try-Catch


Try-Catch문은 예를 들면, 웹이나 디바이스에 접근하는 예외를 프로그래머가 제어하기 위해서 사용이 됩니다.

하지만, Try-Catch문 때문에 소스 코드의 수행 시간은 늘어지니, 최대한 Try-Catch문의 코드는 단순하게 구성해야 합니다.


Replace Division


C#에선 Division의 Replace가 상대적으로 느립니다. 한 가지 방법으론 C#의 소스 코드를 최적화하기 위해 Multiplication-shift operation 부분을 다른 방식으로 대체하는 겁니다.



출처 1 - 10 C# Shorthands that improve productivity (링크 깨짐)

출처 2 - 7 Ways To Optimize C# Code



http://codingcoding.tistory.com/330 

반응형
반응형



문자열은 값이 텍스트인 String 형식의 개체입니다. 내부적으로 텍스트는 Char 개체의 순차적 읽기 전용 컬렉션으로 저장됩니다. C# 문자열의 끝에 null 종료 문자가 없으므로 C# 문자열에는 포함된 null 문자('\0')를 여러 개 사용할 수 있습니다. 문자열의 Length 속성은 유니코드 문자 수가 아닌 포함된 Char 개체 수를 나타냅니다. 문자열에서 개별 유니코드 코드 포인트에 액세스하려면 StringInfo 개체를 사용합니다.

문자열과 System.String

C#에서 string 키워드는 String의 별칭입니다. 따라서 String 및 string은 동일하며 원하는 명명 규칙을 사용할 수 있습니다. String 클래스는 문자열을 안전하게 작성, 조작 및 비교할 수 있도록 다양한 메서드를 제공합니다. 또한 C# 언어는 일반적인 문자열 작업을 간소화 하기 위해 일부 연산자를 오버로드합니다. 키워드에 대한 자세한 내용은 string을 참조하세요. 형식 및 메서드에 대한 자세한 내용은 String을 참조하세요.

문자열 선언 및 초기화

다음 예제에서와 같이 다양한 방법으로 문자열을 선언하고 초기화할 수 있습니다.

C#
// Declare without initializing.
string message1;

// Initialize to null.
string message2 = null;

// Initialize as an empty string.
// Use the Empty constant instead of the literal "".
string message3 = System.String.Empty;

//Initialize with a regular string literal.
string oldPath = "c:\\Program Files\\Microsoft Visual Studio 8.0";

// Initialize with a verbatim string literal.
string newPath = @"c:\Program Files\Microsoft Visual Studio 9.0";

// Use System.String if you prefer.
System.String greeting = "Hello World!";

// In local variables (i.e. within a method body)
// you can use implicit typing.
var temp = "I'm still a strongly-typed System.String!";

// Use a const string to prevent 'message4' from
// being used to store another string value.
const string message4 = "You can't get rid of me!";

// Use the String constructor only when creating
// a string from a char*, char[], or sbyte*. See
// System.String documentation for details.
char[] letters = { 'A', 'B', 'C' };
string alphabet = new string(letters);

문자 배열이 포함된 문자열을 초기화할 경우를 제외하고는 문자열 개체를 만들기 위해 new 연산자를 사용하지 않습니다.

문자열 길이가 0인 새 String 개체를 만들려면 Empty 상수 값이 포함된 문자열을 초기화하세요. 빈 문자열을 문자열 리터럴로 나타내면 ""로 표시됩니다. null 대신 Empty 값이 포함된 문자열을 초기화하면 NullReferenceException 발생을 줄일 수 있습니다. 액세스하기 전에 문자열의 값을 확인하려면 정적 IsNullOrEmpty(String) 메서드를 사용하세요.

문자열 개체의 불변성

문자열 개체는 변경할 수 없습니다. 즉, 생성된 후에는 바꿀 수 없습니다. 실제로 문자열을 수정하는 것으로 나타나는 모든 String 메서드 및 C# 연산자는 새로운 문자열 개체에 결과를 반환합니다. 다음 예제에서 s1  s2의 콘텐츠는 단일 문자열을 형성하도록 연결되며, 두 개의 원본 문자열은 변경되지 않습니다. += 연산자는 결합된 콘텐츠를 포함하는 새 문자열을 만듭니다. 새 개체는 s1 변수에 할당되며, 참조를 유지하는 변수가 없으므로 s1에 할당된 원래 개체는 가비지 수집을 위해 해제됩니다.

C#
string s1 = "A string is more ";
string s2 = "than the sum of its chars.";

// Concatenate s1 and s2. This actually creates a new
// string object and stores it in s1, releasing the
// reference to the original object.
s1 += s2;

System.Console.WriteLine(s1);
// Output: A string is more than the sum of its chars.

문자열 "수정"은 실제로 새 문자열을 만드는 것이므로 문자열에 대한 참조를 만들 때 주의해야 합니다. 문자열에 대한 참조를 만든 후 원래 문자열을 "수정"하더라도 참조는 문자열을 수정할 때 만든 새 개체가 아니라 원래 개체를 계속 가리킵니다. 이 동작은 다음 코드에서 볼 수 있습니다.

C#
string s1 = "Hello ";
string s2 = s1;
s1 += "World";

System.Console.WriteLine(s2);
//Output: Hello

원래 문자열에 대한 검색 및 바꾸기 작업과 같이, 수정을 기반으로 하는 새 문자열 작성 방법에 대한 자세한 내용은 방법: 문자열 콘텐츠 수정을 참조하세요.

일반 및 축자 문자열 리터럴

다음 예제와 같이 C#에서 제공하는 이스케이프 문자를 포함해야 하는 경우 일반 문자열 리터럴을 사용합니다.

C#
string columns = "Column 1\tColumn 2\tColumn 3";
//Output: Column 1        Column 2        Column 3

string rows = "Row 1\r\nRow 2\r\nRow 3";
/* Output:
  Row 1
  Row 2
  Row 3
*/

string title = "\"The \u00C6olean Harp\", by Samuel Taylor Coleridge";
//Output: "The Æolean Harp", by Samuel Taylor Coleridge

문자열 텍스트에 백슬래시 문자가 포함된 경우 가독성을 높이고 편의를 위해 축자 문자열을 사용합니다(예: 파일 경로). 축자 문자열에서는 문자열 텍스트의 일부로 줄 바꿈 문자가 유지되므로 여러 줄 문자열을 초기화하는 데 사용할 수 있습니다. 축자 문자열 내에 따옴표를 포함하려면 큰따옴표를 사용하세요. 다음 예제에서는 몇 가지 일반적인 축자 문자열에 대한 사용을 보여 줍니다.

C#
string filePath = @"C:\Users\scoleridge\Documents\";
//Output: C:\Users\scoleridge\Documents\

string text = @"My pensive SARA ! thy soft cheek reclined
    Thus on mine arm, most soothing sweet it is
    To sit beside our Cot,...";
/* Output:
My pensive SARA ! thy soft cheek reclined
   Thus on mine arm, most soothing sweet it is
   To sit beside our Cot,... 
*/

string quote = @"Her name was ""Sara.""";
//Output: Her name was "Sara."

문자열 이스케이프 시퀀스

이스케이프 시퀀스문자 이름유니코드 인코딩
\'작은따옴표0x0027
\"큰따옴표0x0022
\\백슬래시0x005C
\0Null0x0000
\a경고0x0007
\b백스페이스0x0008
\f폼 피드0x000C
\n줄 바꿈0x000A
\r캐리지 리턴0x000D
\t가로 탭0x0009
\U서로게이트 쌍의 경우 유니코드 이스케이프 시퀀스\Unnnnnnnn
\u유니코드 이스케이프 시퀀스\u0041 = "A"
\v세로 탭0x000B
\x길이가 변하는 경우를 제외하고 "\u"와 유사한 유니코드 이스케이프 시퀀스합니다.\x0041 = "A"
참고

컴파일 시 축자 문자열은 모두 동일한 이스케이프 시퀀스가 포함된 일반 문자열로 변환됩니다. 따라서 디버거 조사식 창에서 축자 문자열을 확인할 경우 소스 코드의 축자 버전이 아니라 컴파일러에 의해 추가된 이스케이프 문자가 나타납니다. 예를 들어 축자 문자열 @"C:\files.txt"는 조사식 창에 "c:\\files.txt"로 나타납니다.

형식 문자열

형식 문자열은 콘텐츠가 런타임 시 동적으로 결정될 수 있는 문자열입니다. 정적 Format 메서드를 사용하고, 런타임 시 다른 값으로 바뀔 자리 표시자를 중괄호에 포함하여 형식 문자열을 만들 수 있습니다. 다음 예제에서는 형식 문자열을 사용하여 루프의 각 반복의 결과를 출력합니다.

C#
class FormatString
{
    static void Main()
    {
        // Get user input.
        System.Console.WriteLine("Enter a number");
        string input = System.Console.ReadLine();

        // Convert the input string to an int.
        int j;
        System.Int32.TryParse(input, out j);

        // Write a different string each iteration.
        string s;
        for (int i = 0; i < 10; i++)
        {
            // A simple format string with no alignment formatting.
            s = System.String.Format("{0} times {1} = {2}", i, j, (i * j));
            System.Console.WriteLine(s);
        }

        //Keep the console window open in debug mode.
        System.Console.ReadKey();
    }
}

WriteLine 메서드를 한 번 오버로드하면 형식 문자열을 매개 변수로 가져옵니다. 따라서 메서드에 대한 명시적 호출이 없어도 형식 문자열 리터럴을 포함할 수 있습니다. 그러나 WriteLine은 형식 문자열이 아닌 문자열만 허용하므로, WriteLine 메서드를 사용하여 Visual Studio 출력 창에 디버그 출력을 표시할 경우에는 Format 메서드를 명시적으로 호출해야 합니다. 형식 문자열에 대한 자세한 내용은 형식 서식 지정을 참조하세요.

부분 문자열

부분 문자열은 문자열에 포함된 임의의 문자 시퀀스입니다. 원래 문자열 일부에서 새 문자열을 만들려면 Substring 메서드를 사용하세요. IndexOf 메서드를 사용하면 부분 문자열 항목을 하나 이상 검색할 수 있습니다. 지정된 부분 문자열의 모든 항목을 새 문자열로 바꾸려면 Replace 메서드를 사용하세요. Substring 메서드와 마찬가지로, Replace는 실제로 새 문자열을 반환하며, 원래 문자열은 수정되지 않습니다. 자세한 내용은 방법: 문자열 메서드를 사용하여 문자열 검색  방법: 문자열 콘텐츠 수정을 참조하세요.

C#
string s3 = "Visual C# Express";
System.Console.WriteLine(s3.Substring(7, 2));
// Output: "C#"

System.Console.WriteLine(s3.Replace("C#", "Basic"));
// Output: "Visual Basic Express"

// Index values are zero-based
int index = s3.IndexOf("C");
// index = 7

개별 문자 액세스

다음 예제와 같이 인덱스 값이 있는 배열 표기법을 사용하여 개별 문자에 대한 읽기 전용 액세스 권한을 얻을 수 있습니다.

C#
string s5 = "Printing backwards";

for (int i = 0; i < s5.Length; i++)
{
    System.Console.Write(s5[s5.Length - i - 1]);
}
// Output: "sdrawkcab gnitnirP"

문자열에서 개별 문자를 수정해야 하는 기능이 String 메서드에서 제공되지 않는 경우에는 StringBuilder 개체를 사용하여 개별 문자를 "현재 위치"에서 수정한 후 새 문자열을 만들어 StringBuilder 메서드로 결과를 저장할 수 있습니다. 다음 예제에서는 특정 방식으로 원래 문자열을 수정한 다음 나중에 사용할 수 있도록 결과를 저장해야 한다고 가정합니다.

C#
string question = "hOW DOES mICROSOFT wORD DEAL WITH THE cAPS lOCK KEY?";
System.Text.StringBuilder sb = new System.Text.StringBuilder(question);

for (int j = 0; j < sb.Length; j++)
{
    if (System.Char.IsLower(sb[j]) == true)
        sb[j] = System.Char.ToUpper(sb[j]);
    else if (System.Char.IsUpper(sb[j]) == true)
        sb[j] = System.Char.ToLower(sb[j]);
}
// Store the new string.
string corrected = sb.ToString();
System.Console.WriteLine(corrected);
// Output: How does Microsoft Word deal with the Caps Lock key?            

null 문자열 및 빈 문자열

빈 문자열은 문자가 포함되지 않은 System.String 개체의 인스턴스입니다. 빈 문자열은 빈 텍스트 필드를 나타내는 다양한 프로그래밍 시나리오에서 자주 사용됩니다. 빈 문자열은 유효한 System.String 개체이므로 빈 문자열에 대해 메서드를 호출할 수 있습니다. 빈 문자열은 다음과 같이 초기화됩니다.

string s = String.Empty;  

반면, null 문자열은 System.String 개체의 인스턴스를 참조하지 않으므로 null 문자열에서 메서드를 호출하려고 하면 NullReferenceException이 발생합니다. 그러나 다른 문자열과 연결 및 비교 작업에서는 null 문자열을 사용할 수 있습니다. 다음 예제에는 null 문자열에 대한 참조로 예외가 발생하거나 발생하지 않는 몇 가지 경우가 나와 있습니다.

C#
static void Main()
{
    string str = "hello";
    string nullStr = null;
    string emptyStr = String.Empty;

    string tempStr = str + nullStr;
    // Output of the following line: hello
    Console.WriteLine(tempStr);

    bool b = (emptyStr == nullStr);
    // Output of the following line: False
    Console.WriteLine(b);

    // The following line creates a new empty string.
    string newStr = emptyStr + nullStr;

    // Null strings and empty strings behave differently. The following
    // two lines display 0.
    Console.WriteLine(emptyStr.Length);
    Console.WriteLine(newStr.Length);
    // The following line raises a NullReferenceException.
    //Console.WriteLine(nullStr.Length);

    // The null character can be displayed and counted, like other chars.
    string s1 = "\x0" + "abc";
    string s2 = "abc" + "\x0";
    // Output of the following line: * abc*
    Console.WriteLine("*" + s1 + "*");
    // Output of the following line: *abc *
    Console.WriteLine("*" + s2 + "*");
    // Output of the following line: 4
    Console.WriteLine(s2.Length);
}

빠른 문자열 생성을 위한 StringBuilder 사용

.NET에서 문자열 작업은 고도로 최적화되어 있으므로 대부분의 경우 성능에 크게 영향을 주지 않습니다. 그러나 수백 번 또는 수천 번 실행하는 타이트 루프와 같은 일부 시나리오에서는 문자열 작업이 성능에 영향을 미칠 수 있습니다. 프로그램이 여러 문자열 조작을 수행하는 경우에는 StringBuilder 클래스에서 개선된 성능을 제공하는 문자열 버퍼를 만듭니다. StringBuilder 문자열을 사용하면 개별 문자를 다시 할당할 수도 있지만 기본 제공 문자열 데이터 형식을 지원하지는 않습니다. 예를 들어 이 코드는 새 문자열을 만들지 않고 문자열의 콘텐츠를 변경합니다.

C#
System.Text.StringBuilder sb = new System.Text.StringBuilder("Rat: the ideal pet");
sb[0] = 'C';
System.Console.WriteLine(sb.ToString());
System.Console.ReadLine();

//Outputs Cat: the ideal pet

이 예제에서 StringBuilder 개체는 숫자 형식 집합에서 문자열을 만드는 데 사용됩니다.

C#
class TestStringBuilder
{
    static void Main()
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        // Create a string composed of numbers 0 - 9
        for (int i = 0; i < 10; i++)
        {
            sb.Append(i.ToString());
        }
        System.Console.WriteLine(sb);  // displays 0123456789

        // Copy one character of the string (not possible with a System.String)
        sb[0] = sb[9];

        System.Console.WriteLine(sb);  // displays 9123456789
    }
}

문자열, 확장 메서드 및 LINQ

String 형식이 IEnumerable<T>을 구현하므로 문자열에서 Enumerable 클래스에 정의된 확장 메서드를 사용할 수 있습니다. 시각적인 혼란을 방지하기 위해 String 형식의 경우 이러한 메서드가 IntelliSense에서 제외되지만, 제외되더라도 사용할 수는 있습니다. 문자열에서 LINQ 쿼리 식을 사용할 수도 있습니다. 자세한 내용은 LINQ 및 문자열을 참조하세요.



https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/strings/


반응형
반응형




프로그램을 하다 보면 모든 것이 Collection 개념입니다.

배열은 당연히 그렇고 SQL 의 테이블, 탐색기, XML 등등..

 

.NET Framework에서 제공하는 기본 Collection 들의 제네릭 버전을 사용하기 위해서는

using System.Collections.Generic; 네임스페이스를 선언해야 합니다.

 

그럼 기본 Collection 중 제네릭 개념의 Collection을 봅시다. ( 같은 기능을 합니다. Generic 버젼이죠 )

    비 제네릭

 제네릭

 비고

 ArrayList

 List<T>

 동적 배열, 처음값:0, 일차원

 Hashtable

 Dictionary<K,V>

 Key와 Value를 쌍으로 저장하는 객체

 SortedList

 SortedList<K,V>

 Key를 기준으로 sorting 되어 관리하는 객체

 Stack

 Stack<T>

 선입후출 : 먼저 들어간 값이 나중에 나오는 객체 

 Queue

 Queue<T>

 선업선출 : 먼저 들어간 값이 먼저 나오는 객체

뭐 이것 말고 몇가지 더 있습니다. 비 제네릭과 제네릭에서 있는 것만..^^;;

인터페이스도 있고.. 뭐 기회가 되면 또 하기로 하고요.

 

이렇게 컬렉션(Collection) 들이 제네릭을 많이 사용합니다. ( 생각해 보면 그러겠죠. 데이터를 넣다 뺐다 해야 되니.. )

 

그럼 하나씩 봅시다. 예제는 제너릭 Collection만 구현 할것입니다. 비 제네릭의 경우는 뭐 특별히 기술은 안하려고요.

은근 캡처가 힘들기도 하고 2개 다 사용방법도 거의 같습니다.

 

1. ArrayList, List<T>

 

배열을 선언할때 미리 크기를 지정하여 사용하였으나 이 구조는 동적으로 배열을 구성할 수 있습니다. ( 편하겠군요 ^^ )

Add,Insert 메소드로 동적으로 데이터가 저장될 수 있습니다.

Remove,RemoveAll,RemoveAt 으로 데이터를 지울 수 있습니다.

배열이니 0 부터 시작합니다.

 

각 메소드에 대해 함 보시면 됩니다.

Remove 메소드는 같은 데이터가 2개이상이 있어도 앞의 한개만 지우는것을 볼수 있습니다.

Capacity 메소드의 경우는 배열의 크기를 볼수 있는데 배열 데이터의 갯수를 보여주는 count 하고는

개념이 틀린겁니다.

 

List 클래스가 동적배열을 할당한다고 했는데 내부에는 미리 배열의 크기를 지정해 놓고 있는겁니다.

배열 데이터의 갯수에 따라 말이죠. 생성시점에 크기는 0으로 지정됩니다 ( 메모리 효율적인듯 하네요 ㅎㅎ )

데이터가 들어오면 4로 지정되고

갯수가 4를 초과하면 크기가 8로, 그 이상이면 16,32 등으로 할당 됩니다.

 

여기선 데이터가 5이니 8로 나오는 군요. ( ArrayList는 초기 할당이 틀립니다. 16부터 입니다 )

 


결과입니다.

뭐 각 메소드들의 0,1 이렇게 잡는 것이 헷깔리시면 그때, 그때 마다 도움말 보시면 됩니다.

저도 뭐..ㅎㅎ

 

 

2. Hashtable,Dictionary<K,V>

 

Dictionary는 Hashtable의 제네릭 버젼입니다.

데이터가 key와 value 한쌍으로 저장되는 Collection 구조입니다.

 

key값은 유일해야 합니다. ( 유일성이 보장되어야 합니다. )

Key 값으로 찾으니 빠른 검색을 할 수 있습니다.

 

Key 와 Value 의 한쌍으로 구성된 Collection 이니 가져오는 방법이나 사용방법도 List 클래스는 차이가 있겠죠.

함 소스 코드를 보시기 바랍니다. ( 넘 말들이 무미건조해 지는듯.. 계속 반복되는 작업에..^^;; )

 

 

결과입니다.


 

 

3. SortedList, SortedList<K,V>

 

이름이 제네릭 버젼과 같습니다. 물론 두개의 네임스페이스는 틀립니다. 뭐 위의 Collection 들도 제너릭버젼과 당연 틀리겠죠.

 

SortedList<K,V>도 Dictionary<K,V> 처럼 Key 와 Value 가 한쌍으로 구성되어 있습니다.

Dictionary 와 사용 방법은 거의 동일합니다.

 

Dictionary 클래스에 Key 값 기준으로 정렬이 되는 것이 특징입니다. 알아서 정렬해 준다는 참 친절한..

 

뭐 기본 사용법만 나열하겠습니다. 다른 내용이 필요하면 도움말로..^^;;

 

예제는 Dictionary 와 SortedList 차이점을 보도록 하겠습니다. Key = 2 를 제일 나중에 추가 하고 배열된 순서대로 찍어 보도록 합니다.

그리고 SortedList는 List가 가지고 있던 동적배열 크기 할당 속성도 가지고 있네요. ( Capacity 항목이 있습니다. )

 


역시 이름에 걸맞게 젤 뒤어 추가해도 Key 값에 정렬되어 나오는 군요. 
Dictionary 는 추가한 순서대로 나오는걸 확인 할수 있습니다.


 

 

4. StackStack<T>

 

참 많이 들어본 키워드 입니다. 앞에 박싱 언방싱 할때 Value Type(값 타입) 개체들이 메모리에 사용되는 방식이죠.

한글로 "쌓다" 라는 단어입니다.

차근 차근 쌓아놓고 있으니 뺄때도 나중에 쌓은 것을 먼저 뺴야죠. 먼저 아래에 넣은 걸 뺴면 무너집니다.

LIFO(Last In First Out) 개념입니다.

 

자 또 봅시다. 계속 만드니 약간 귀찮아 질려는...쩝.. 그래도 몇개 안남았으니 열심히 해보겠습니다.

 

stack 은 Add/Remove 메소드가 아닌 Push/Pop으로 데이터를 넣고 빼고 합니다.

Pop() 메소드는 제일 위에 있는 데이터를 삭제하고

Peek() 메소드는 제일 위에 있는 데이터를 불러옵니다.

 

이러한 형태는 우리가 웹브라우져에서 앞으로 뒤로 가기 하면 최근 항목이 나오는데 그런 방식에 유용합니다.

 


역시 결과가 잘 나옵니다.

뭐 하나 하나 씩 살펴 보시면 됩니다.

 

스택 오버 플로워(StackOverFlow) 는 Stack 이 꽉 찼을때 발생합니다.

 

 

5. QueueQueue<T>

 

Queue는  Stack 과 상반되는 내용입니다. 먼저 들어간 것이 먼저 나오는 거죠FIFO(First In First Out) 라 표현 됩니다.

예를 들면 메일, 프린터 등과 같은 곳에서 사용 됩니다.

 

Queue는 Enqueue 로 값을 넣고 하나씩 Dequeue 로 값을 뺴 내면서 데이터를 없애는 식의 작업을 합니다. 

보시면 Enqueue / Dequeue 를 제외하곤 사용이 Stack 과 비슷하니 이해하기는 쉬울듯 하네요.

 


역시 잘 나오죠 ^^

그 외에 제네릭 버젼에만 있는 LinkedList<T>, ReadOnlyCollection<T>,KeyedCollection(K,V) 등은 추후에 다시 기술 하도록 하겟습니다.

 

Collection 에서 제네릭은 박싱/언박싱 에 따른 부하도 감소 할 수 있지만

미리 타입을 지정함으로써 잘못된 코드들에 대한 검증도 컴파일 단계에서 알 수 있게 해줍니다.

오류를 감소 시켜주는 거죠.

 

이번 시간엔 Collection 에 대한 예제만 보여드렸습니다. ( 개인적으론 약간 지루한.. ^^;; )

 

다음 시간엔 제너릭이 다른 형식으로 쓰이는 부분에 대해 말씀드리도록 하겠습니다.

 

수고 하십시요

 


반응형

+ Recent posts