'사용'지시문이 네임 스페이스 내부 또는 외부에 있어야합니까?


2060

C # 코드를 통해 StyleCop 을 실행 했으며 내 using지시문이 네임 스페이스 안에 있어야한다고 보고합니다 .

using네임 스페이스 외부가 아닌 내부 에 지시문 을 배치해야하는 기술적 이유가 있습니까?


4
: 때때로 당신은 using이를 넣어 차이가 있습니다 stackoverflow.com/questions/292535/linq-to-sql-designer-bug
gius

82
참고로 파일 당 여러 클래스의 문제를 넘어서는 의미가 있으므로이 질문을 처음 접하는 경우 계속 읽으십시오.
Charlie

3
@ user-12506-어느 정도의 코드 일관성이 필요한 중대형 개발 팀에서는이 기능이 제대로 작동하지 않습니다. 앞에서 언급했듯이 다른 레이아웃을 이해하지 못하면 예상대로 작동하지 않는 경우가 있습니다.
benPearce

34
용어 : 이것은 using 진술 이 아닙니다 . 그것들은 using 지시어 입니다. using문 한편, 예에있어서 본체의 내부 등, 다른 문장들과 함께 발생하는 언어 구조, using (var e = s.GetEnumerator()) { /* ... */ }느슨하게과 동일한 성명이다 var e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }.
Jeppe Stig Nielsen

1
이 글을 아직 아무도 언급하지 않았다면, 실제로 Microsoft 는 내부 코딩 지침 에서 선언문 에 using문장을 넣는 것을 권장합니다.namespace
user1451111

답변:


2132

실제로 둘 사이에는 (미묘한) 차이가 있습니다. File1.cs에 다음 코드가 있다고 가정하십시오.

// File1.cs
using System;
namespace Outer.Inner
{
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

이제 누군가 다음과 같은 다른 파일 (File2.cs)을 프로젝트에 추가한다고 상상해보십시오.

// File2.cs
namespace Outer
{
    class Math
    {
    }
}

컴파일러 는 네임 스페이스 외부 Outer에서 해당 using지시문을보기 전에 검색 하므로 Outer.Math대신 대신 찾습니다 System.Math. 불행하게도 (혹은 다행히도?), Outer.Math어떤이 없습니다 PI을 File1 지금 파괴되도록, 멤버.

using네임 스페이스 선언 내부에 다음과 같이 넣으면 변경됩니다 .

// File1b.cs
namespace Outer.Inner
{
    using System;
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

이제 컴파일러는 검색 System하기 전에 검색 Outer하고 찾기 만하면 System.Math됩니다.

일부는 Math이미 사용자 정의 클래스의 이름이 잘못되었을 수 있다고 주장합니다 System. 여기서 요점은 차이점 있으며 코드 유지 관리에 영향을 미친다는 것입니다.

또한 Foonamespace Outer가 아니라 namespace에 있으면 어떻게되는지 주목하는 것도 흥미 롭습니다 Outer.Inner. 이 경우 Outer.MathFile2에 추가 하면 using이동 위치에 관계없이 File1이 중단 됩니다. 이는 컴파일러가 using지시문을 보기 전에 가장 안쪽의 네임 스페이스를 검색 함을 의미합니다 .


28
이것이 Mark의 다중 네임 스페이스-인-일-파일 인수보다 로컬로 명령문을 사용하는 것이 훨씬 더 좋은 이유입니다. 특히 사인을 컴파일하면 이름 충돌에 대해 불평 할 수 있습니다 (예를 들어 Jared가 게시 한 규칙에 대한 StyleCop 설명서 참조).
David Schmitt

148
허용되는 답변은 좋지만 네임 스페이스 외부에 using 절을 넣는 것이 좋은 이유 인 것 같습니다 . 네임 스페이스 Outer.Inner에 있으면 System.Math가 아닌 Outer.Inner의 Math 클래스를 사용할 것으로 예상됩니다.
Frank Wallis

7
나는 이것에도 동의합니다. 허용되는 답변은 기술적으로 차이점을 설명하는 것입니다. 그러나 하나 또는 다른 클래스에는 명시적인 콜 아웃이 필요합니다. "Math"를 내 로컬 클래스로 확인하고 "System.Math"는 외부 클래스를 참조합니다. Outer.Math가 존재하기 전에 System.Math가 "Math"로 사용 된 경우에도 마찬가지입니다. 그렇습니다. 그러나 기존의 많은 참조를 수정하는 것이 더 효과적이지만 Outer.Math의 이름이 다른 힌트 일 수도 있습니다.
mbmcavoy

13
큰 대답이지만, 문을 사용하여 비 프레임 워크를 로컬에 넣고 문을 사용하여 프레임 워크를 전역으로 유지하고 싶습니다. 왜 내가 선호도를 완전히 바꿔야하는지에 대한 추가 설명이 있습니까? 또한 VS2008의 템플릿은 네임 스페이스 외부를 사용하여 어디에서 왔습니까?
Thymine

31
나는 이것이 당신의 사용 장소를 바꾸는 것이 아니라 나쁜 명명 규칙이라고 생각합니다. 솔루션에 Math라는 클래스가 없어야합니다
jDeveloper

454

이 스레드에는 이미 훌륭한 답변이 있지만이 추가 답변으로 조금 더 자세하게 가져올 수 있다고 생각합니다.

먼저 마침표가있는 네임 스페이스 선언은 다음과 같습니다.

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    ...
}

전적으로 다음과 같습니다.

namespace MyCorp
{
    namespace TheProduct
    {
        namespace SomeModule
        {
            namespace Utilities
            {
                ...
            }
        }
    }
}

원하는 경우 using이러한 모든 수준 에 지시문을 둘 수 있습니다. (물론, 우리 using는 한 곳에만 있기를 원하지만 언어에 따라 합법적입니다.)

어떤 유형이 암시되는지 확인하는 규칙은 다음과 같이 느슨하게 설명 할 수 있습니다. 먼저 일치하는 가장 안쪽의 "범위"를 검색합니다. 아무것도 발견되지 않으면 다음 범위로 한 레벨 이동하여 검색합니다 . 일치하는 것을 찾을 때까지. 어떤 수준에서 두 개 이상의 일치하는 항목이 발견되면 유형 중 하나가 현재 어셈블리에서 온 경우 해당 유형을 선택하고 컴파일러 경고를 발행하십시오. 그렇지 않으면 포기 (컴파일 타임 오류)합니다.

이제 두 가지 주요 규칙이있는 구체적인 예에서 이것이 무엇을 의미하는지 명시 해 보겠습니다.

(1) 외부 사용시 :

using System;
using System.Collections.Generic;
using System.Linq;
//using MyCorp.TheProduct;  <-- uncommenting this would change nothing
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    class C
    {
        Ambiguous a;
    }
}

위의 경우 어떤 유형인지 확인 Ambiguous하려면 다음 순서로 검색하십시오.

  1. 내부의 중첩 유형 C(상속 된 중첩 유형 포함)
  2. 현재 네임 스페이스의 유형 MyCorp.TheProduct.SomeModule.Utilities
  3. 네임 스페이스의 유형 MyCorp.TheProduct.SomeModule
  4. 유형 MyCorp.TheProduct
  5. 유형 MyCorp
  6. 의 유형 네임 스페이스 (전역 네임 스페이스)
  7. 유형에서 System, System.Collections.Generic, System.Linq, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, 및ThirdParty

다른 컨벤션 :

(2) 내부 사용시 :

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using MyCorp.TheProduct;                           // MyCorp can be left out; this using is NOT redundant
    using MyCorp.TheProduct.OtherModule;               // MyCorp.TheProduct can be left out
    using MyCorp.TheProduct.OtherModule.Integration;   // MyCorp.TheProduct can be left out
    using ThirdParty;

    class C
    {
        Ambiguous a;
    }
}

이제 유형 검색 Ambiguous은 다음 순서로 진행됩니다.

  1. 내부의 중첩 유형 C(상속 된 중첩 유형 포함)
  2. 현재 네임 스페이스의 유형 MyCorp.TheProduct.SomeModule.Utilities
  3. 유형에서 System, System.Collections.Generic, System.Linq, MyCorp.TheProduct, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, 및ThirdParty
  4. 네임 스페이스의 유형 MyCorp.TheProduct.SomeModule
  5. 유형 MyCorp
  6. 의 유형 네임 스페이스 (전역 네임 스페이스)

( MyCorp.TheProduct이는 "3."의 일부이므로 "4."와 "5."사이에는 필요하지 않았습니다.)

끝 맺는 말

네임 스페이스 선언 내부 또는 외부에 용도를 사용하더라도 나중에 누군가가 우선 순위가 더 높은 네임 스페이스 중 하나에 동일한 이름의 새 유형을 추가 할 가능성이 항상 있습니다.

또한 중첩 네임 스페이스가 유형과 이름이 같은 경우 문제가 발생할 수 있습니다.

검색 계층 구조가 변경되고 다른 유형이있을 수 있으므로 사용을 한 위치에서 다른 위치로 옮기는 것은 항상 위험합니다. 따라서 하나의 규칙을 선택하고 준수하여 사용을 이동할 필요가 없습니다.

Visual Studio의 템플릿은 기본적으로 용도를 네임 스페이스 외부 에 둡니다 (예 : VS가 새 파일에서 새 클래스를 생성하도록하는 경우).

외부 에서 사용하는 것의 가장 작은 장점은 예를 들어 [assembly: ComVisible(false)]대신 전역 속성에 대해 using 지시문을 사용할 수 있다는 것입니다 [assembly: System.Runtime.InteropServices.ComVisible(false)].


46
이것은 '사용'진술의 위치가 개발자의 고의적 인 결정이라는 사실을 강조하기 때문에 가장 좋은 설명입니다. 어떤 경우에도 누군가가 의미를 이해하지 않고 '사용'진술의 위치를 ​​부주의하게 변경해서는 안됩니다. 따라서 StyleCop 규칙은 바보입니다.
ZunTzu

194

네임 스페이스에 넣으면 파일에 대한 네임 스페이스에 대한 선언이 파일에 대해 로컬로 만들어 지지만 (파일에 여러 네임 스페이스가있는 경우) 파일 당 하나의 네임 스페이스 만있는 경우 외부 또는 외부에 상관없이 큰 차이가 없습니다. 네임 스페이스 내부

using ThisNamespace.IsImported.InAllNamespaces.Here;

namespace Namespace1
{ 
   using ThisNamespace.IsImported.InNamespace1.AndNamespace2;

   namespace Namespace2
   { 
      using ThisNamespace.IsImported.InJustNamespace2;
   }       
}

namespace Namespace3
{ 
   using ThisNamespace.IsImported.InJustNamespace3;
}

네임 스페이스는 물리적 (파일)이 아닌 논리적 구분을 제공합니다.
Jowen

9
차이가 없다는 것은 사실이 아닙니다. 블록 using내의 지시문 namespace은 둘러싸는 namespace블록을 기반으로 상대 네임 스페이스를 참조 할 수 있습니다 .
또는 매퍼

70
그래 알아 우리는이 질문에 5 년 전에 받아 들여진 대답을 확립했습니다.
Mark Cidade

59

에 따르면 Hanselman은 - 지침 및 조립로드 ... 사용 및 기타 제품은 기술적으로 차이가 없다.

선호하는 것은 네임 스페이스 외부에 배치하는 것입니다.


3
@Chris M : 어 ... 답변에 게시 된 링크는 vs.에 이점이 없음을 나타내며 실제로 게시 한 링크에서 제기 된 주장을 위조하는 예를 보여줍니다.
johnny

2
Aye 나는 스레드를 완전히 읽지 못했지만 MVP가 옳다고 말했을 때 구입했습니다. 한 사람이 그것을 반증하고 설명하고 코드를 더 자세히 보여줍니다 ... "C # 컴파일러가 생성하는 IL은 어느 경우 든 동일합니다. 실제로 C # 컴파일러는 각 using 지시문에 해당하는 것을 정확히 생성하지 않습니다. 지시문을 사용하는 것은 순전히 a입니다. C # ism이며 .NET 자체에는 의미가 없습니다. (구문을 사용하는 경우에는 사실이 아니지만 매우 다릅니다.) " groups.google.com/group/wpf-disciples/msg/781738deb0a15c46
Chris McKee

84
링크 요약을 포함하십시오. 링크가 깨진 (이 때문에 것입니다 갑자기 32 upvotes와 답변은 가치가있다, 일, 충분한 시간을 주어) My style is to put them outside the namespaces.거의 답변 모두에서 -.
ANeves

11
여기에 대한 주장은 단순히 잘못되었습니다 ... 기술적 인 차이가 있으며 자신의 인용이 그렇게 말합니다 ... 사실 그것이 그게 전부입니다. 이 오답을 삭제하십시오 ... 훨씬 더 정확하고 정확한 답변이 있습니다.
Jim Balter

53

StyleCop 설명서에 따르면 :

SA1200 : 네임 스페이스에서 지시문 사용

원인 AC # using 지시문이 네임 스페이스 요소 외부에 배치되었습니다.

규칙 설명이 규칙의 위반은 파일에 네임 스페이스 요소가 포함되지 않은 경우 using 지시문 또는 using-alias 지시문이 네임 스페이스 요소 외부에 배치 될 때 발생합니다.

예를 들어 다음 코드는이 규칙을 두 번 위반합니다.

using System;
using Guid = System.Guid;

namespace Microsoft.Sample
{
    public class Program
    {
    }
}

그러나 다음 코드는이 규칙을 위반하지 않습니다.

namespace Microsoft.Sample
{
    using System;
    using Guid = System.Guid;

    public class Program
    {
    }
}

이 코드는 컴파일러 오류없이 깨끗하게 컴파일됩니다. 그러나 어떤 버전의 Guid 유형이 할당되고 있는지 확실하지 않습니다. 아래와 같이 using 지시문을 네임 스페이스 내부로 이동하면 컴파일러 오류가 발생합니다.

namespace Microsoft.Sample
{
    using Guid = System.Guid;
    public class Guid
    {
        public Guid(string s)
        {
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Guid g = new Guid("hello");
        }
    }
}

다음 컴파일러 오류로 인해 코드가 실패합니다. Guid g = new Guid("hello");

CS0576 : 네임 스페이스 'Microsoft.Sample'에 별칭 'Guid'와 충돌하는 정의가 포함되어 있습니다.

이 코드는 Guid라는 System.Guid 형식에 대한 별칭을 만들고 일치하는 생성자 인터페이스를 사용하여 Guid라는 자체 형식을 만듭니다. 나중에이 코드는 Guid 유형의 인스턴스를 만듭니다. 이 인스턴스를 만들려면 컴파일러가 Guid의 두 가지 다른 정의 중에서 선택해야합니다. using-alias 지시문이 namespace 요소 외부에 배치되면 컴파일러는 로컬 네임 스페이스 내에 정의 된 Guid의 로컬 정의를 선택하고 네임 스페이스 외부에 정의 된 using-alias 지시문을 완전히 무시합니다. 불행히도 이것은 코드를 읽을 때 분명하지 않습니다.

그러나 using-alias 지시문이 네임 스페이스 내에 있으면 컴파일러는 동일한 네임 스페이스 내에 정의 된 서로 상충되는 두 가지 Guid 유형 중에서 선택해야합니다. 이 두 유형 모두 일치하는 생성자를 제공합니다. 컴파일러가 결정을 내릴 수 없으므로 컴파일러 오류를 표시합니다.

using-alias 지시문을 네임 스페이스 외부에 배치하면 실제로 사용되는 유형의 버전이 확실하지 않은 상황에서 혼동을 일으킬 수 있으므로 나쁜 습관입니다. 이로 인해 잠재적으로 진단하기 어려운 버그가 발생할 수 있습니다.

네임 스페이스 요소 내에 using-alias 지시문을 배치하면이를 버그의 원인으로 사용할 수 없습니다.

  1. 여러 네임 스페이스

단일 파일 내에 여러 네임 스페이스 요소를 배치하는 것은 일반적으로 좋지 않은 방법이지만 이것이 완료되면 전역 적으로 파일의 맨 위가 아닌 각 네임 스페이스 요소 내에 모든 사용 지시문을 배치하는 것이 좋습니다. 이렇게하면 네임 스페이스의 범위가 좁아지고 위에서 설명한 동작을 피하는 데 도움이됩니다.

네임 스페이스 외부에있는 지시문을 사용하여 코드를 작성한 경우 네임 스페이스 내에서 이러한 지시문을 이동할 때 코드의 의미가 변경되지 않도록주의해야합니다. 위에서 설명한 바와 같이, 네임 스페이스 요소 내에 using-alias 지시문을 배치하면 컴파일러가 지시문이 네임 스페이스 외부에 배치 될 때 발생하지 않는 방식으로 충돌하는 유형 중에서 선택할 수 있습니다.

위반을 수정하는 방법이 규칙의 위반을 수정하려면 네임 스페이스 요소 내에서 using using 지시문과 using-alias 지시문을 모두 이동하십시오.


1
@Jared-대답에서 언급했듯이 선호하는 해결 방법 / 솔루션은 파일 당 하나의 클래스 만 갖는 것입니다. 나는 이것이 일반적인 관습이라고 생각합니다.
benPearce

24
실제로 StyleCop 규칙이기도합니다! SA1402 : AC # 문서는 모든 클래스가 부분적이고 동일한 유형이 아닌 경우 루트 수준에서 단일 클래스 만 포함 할 수 있습니다. 다른 규칙을 어기면서 하나의 규칙을 보여주는 것은 잘못된 소스로 물을 뿌립니다.
작업

6
StyleCop 관점에서 실제로이를 다루는 첫 번째 답변으로 선정되었습니다. 개인적으로 저는 using네임 스페이스 외부의 시각적 느낌을 좋아합니다 . 내부 using는 나에게 너무 못 생겼습니다. :)
nawfal

2
마지막으로 질문에 대한 좋은 답변입니다. 그리고 benPearce의 의견은 관련이 없습니다 ... 이것은 파일의 클래스 수와 관련이 없습니다.
Jim Balter

35

별칭을 사용하려는 경우 네임 스페이스 내에 using 문을 배치하는 데 문제가 있습니다. 별명은 이전 using명령문의 이점을 얻지 못하며 완전한 규정이어야합니다.

치다:

namespace MyNamespace
{
    using System;
    using MyAlias = System.DateTime;

    class MyClass
    {
    }
}

대:

using System;

namespace MyNamespace
{
    using MyAlias = DateTime;

    class MyClass
    {
    }
}

이것은 다음과 같은 긴 별칭을 가진 경우 특히 두드러 질 수 있습니다 (문제를 발견 한 방법).

using MyAlias = Tuple<Expression<Func<DateTime, object>>, Expression<Func<TimeSpan, object>>>;

함께 using네임 스페이스 내부의 문, 갑자기된다 :

using MyAlias = System.Tuple<System.Linq.Expressions.Expression<System.Func<System.DateTime, object>>, System.Linq.Expressions.Expression<System.Func<System.TimeSpan, object>>>;

예쁘지 않은.


1
귀하의 class요구에 이름 (식별자). using지시 한대로 클래스 안에 지시어를 가질 수 없습니다 . 네임 스페이스 수준에 있어야합니다 (예 : 가장 바깥 쪽 외부 namespace또는 가장 안쪽 안쪽 namespace(클래스 / 인터페이스 등이 아님)).
Jeppe Stig Nielsen

@JeppeStigNielsen 감사합니다. using지시문을 잘못 배치했습니다 . 의도 한대로 편집했습니다. 지적 해 주셔서 감사합니다. 그러나 추론은 여전히 ​​동일합니다.
Neo

4

Jeppe Stig Nielsen이 말했듯 이이 스레드에는 이미 큰 대답이 있지만이 명백한 미묘함도 언급 할 가치가 있다고 생각했습니다.

using 네임 스페이스 내에 지정된 지시문은 외부에서 지정된 것처럼 정규화 될 필요가 없기 때문에 더 짧은 코드를 만들 수 있습니다.

유형 때문에 다음 예제는 작동 Foo하고 Bar같은 글로벌 네임 스페이스에 모두 있습니다 Outer.

코드 파일 Foo.cs를 가정하십시오 .

namespace Outer.Inner
{
    class Foo { }
}

그리고 Bar.cs :

namespace Outer
{
    using Outer.Inner;

    class Bar
    {
        public Foo foo;
    }
}

using지시문 에서 외부 네임 스페이스를 생략 할 수 있습니다 .

namespace Outer
{
    using Inner;

    class Bar
    {
        public Foo foo;
    }
}

8
"외부 네임 스페이스를 생략 할 수있다"는 것이 사실이지만, 반드시 그렇지는 않습니다. 나에게 이것은 @Neo의 답변과 같은 별칭 이외의 지시문을 사용하여 네임 스페이스 외부로 이동하여 정규화 된 네임 스페이스 이름을 강제 해야하는 이유에 대한 또 다른 주장입니다.
Keith Robertson

4

하나의 주름이 발생했습니다 (다른 답변에서는 다루지 않음).

다음 네임 스페이스가 있다고 가정하십시오.

  • 다른 것
  • 부모. 뭔가. 기타

using Something.Other 외부 에서 사용 namespace Parent하는 경우 첫 번째 (Something.Other)를 나타냅니다.

그러나 네임 스페이스 선언 에서 사용 하면 두 번째 네임 스페이스 (Parent.Something.Other)를 나타냅니다!

간단한 해결책이 있습니다 : " global::"접두사 추가 : docs

namespace Parent
{
   using global::Something.Other;
   // etc
}

2

기술적 인 이유는 답변에서 설명하고 나는 차이가 아니기 때문에 그것은 결국 개인 취향에 달려있는 것 같아요 그들 중 모두 장단점이 있습니다. 파일을 만들기위한 Visual Studio의 기본 템플릿 은 네임 스페이스 외부에서 지시문을 .cs사용 using합니다.

다음과 같이 프로젝트 파일의 루트에 파일 using을 추가하여 네임 스페이스 외부의 지시문 을 확인하도록 stylecop를 조정할 수 있습니다 stylecop.json.

{
  "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
    "orderingRules": {
      "usingDirectivesPlacement": "outsideNamespace"
    }
  }
}

이 구성 파일을 솔루션 레벨에서 작성하고 프로젝트에 '기존 링크 파일'로 추가하여 모든 프로젝트에서 구성을 공유 할 수 있습니다.


2

내가 믿지 않는 또 다른 미묘한 점은 같은 이름의 클래스와 네임 스페이스가있을 때입니다.

네임 스페이스 안에 가져 오기가 있으면 클래스를 찾습니다. 가져 오기가 네임 스페이스 외부에 있으면 가져 오기가 무시되고 클래스와 네임 스페이스가 정규화되어야합니다.

//file1.cs
namespace Foo
{
    class Foo
    {
    }
}

//file2.cs
namespace ConsoleApp3
{
    using Foo;
    class Program
    {
        static void Main(string[] args)
        {
            //This will allow you to use the class
            Foo test = new Foo();
        }
    }
}

//file2.cs
using Foo; //Unused and redundant    
namespace Bar
{
    class Bar
    {
        Bar()
        {
            Foo.Foo test = new Foo.Foo();
            Foo test = new Foo(); //will give you an error that a namespace is being used like a class.
        }
    }
}

-8

소스 솔루션에 사용 된 " reference "를 사용 하는 기본값 이 네임 스페이스 외부에 있어야하고 "새로 추가 된 참조"인 것이 네임 스페이스 안에 두는 것이 좋습니다. 이것은 어떤 참조가 추가되고 있는지 구별하기위한 것입니다.


6
아니요, 실제로는 나쁜 생각입니다. 지시어가 새로 추가되었는지 여부에 따라 로컬로 사용되는 지시문과 로컬로 사용되는 지시문 사이의 위치를 ​​기반으로해서는 안됩니다. 대신 BCL 참조를 제외하고 알파벳순으로 정렬하는 것이 좋습니다.
Abel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.