Post

C# 에서 상속된 객체의 Property 를 코드에 작성된 순서대로 정렬해서 보여주는 꼼수

C#처럼 강력한 Reflection 을 지원 하는 언어에서는, Attribute(Java의 Annotaion, Python의 Decorator 와 비슷함) 를 Property 에 붙여서 특수한 용도를 부여 하는 경우가 있다. 특히 노출 되는 Property를 스캔해서 UI를 만들어 주거나 하는 경우도 많은데… 다음 코드를 한번 보자

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
using System.Reflection;

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class KooAttribute : Attribute
{

}

public class Foo
{
    [Koo]
    public string A1 { get; set; }
    [Koo]
    public string A2 { get; set; }
    [Koo]
    public string A3 { get; set; }
    [Koo]
    public string A4 { get; set; }
}

public class Boo : Foo
{
    [Koo]
    public string B1 { get; set; }
    [Koo]
    public string B2 { get; set; }
    [Koo]
    public string B3 { get; set; }
    [Koo]
    public string B4 { get; set; }
}

public class Program
{
    public static void Main(string[] argv)
    {
        typeof(Boo).GetProperties()
            .Where(x => x.GetCustomAttribute<KooAttribute>() != null)
            .ToList()
            .ForEach(x => Console.WriteLine(x.Name));
    }
}

실행 결과가 예측이 되는가? 정답은 아래와 같다

1
2
3
4
5
6
7
8
B1
B2
B3
B4
A1
A2
A3
A4

Property를 스캔할 때, 일단 해당 객체의 Property 를 체크 후, 상속한 부모를 역순으로 되짚어 가며 스캔 하기 때문 인 것 같다. 하지만 보통 저런 경우, 부모가 가진 공통 속성을 먼저 보여주는것이 UI 가 자연스러운 경우가 대부분이다. 그런경우 쓸 수 있는 간단한 트릭을 소개한다.

Attibute를 아래처럼 고친다

1
2
3
4
5
6
7
8
9
10
11
12
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class KooAttribute : Attribute
{
	public readonly int LineNumber;
	public readonly string FilePath;	

	public KooAttribute([CallerLineNumber] int lineNumber = 0, [CallerFilePath] string filePath = "")
	{
		LineNumber = lineNumber;
		FilePath = filePath;		
	}
}

그리고 출력부분을 아래와 같이 고친다

1
2
3
4
5
6
7
8
9
10
public static void Main(string[] argv)
{
	typeof(Boo).GetProperties()
		.Select(i => (property: i, attribute: i.GetCustomAttribute<KooAttribute>()))
		.Where(x => x.attribute != null)
		.OrderBy(x => (x.attribute.FilePath, x.attribute.LineNumber))
		.Select(x => x.property)
		.ToList()
		.ForEach(x => Console.WriteLine(x.Name));
}

Soruce Code 의 LineNumber 를 Attribute 에 박아 넣어 그 순서대로 정렬을 하면, 기본적인 정렬이 가능하다. 만약 순서를 추가로 조정하고 싶다면 FilePath 와 LineNumber 를 임의로 조작 해 주면 큰 문제 없이 원하는 순서대로 세팅이 가능하다.

위와 같이 출력 할 경우 A1~B4 까지 코드에 적인 순서대로 나오게 된다

This post is licensed under CC BY 4.0 by the author.