수색…
사용자 지정 특성 만들기
//1) All attributes should be inherited from System.Attribute
//2) You can customize your attribute usage (e.g. place restrictions) by using System.AttributeUsage Attribute
//3) You can use this attribute only via reflection in the way it is supposed to be used
//4) MethodMetadataAttribute is just a name. You can use it without "Attribute" postfix - e.g. [MethodMetadata("This text could be retrieved via reflection")].
//5) You can overload an attribute constructors
[System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Class)]
public class MethodMetadataAttribute : System.Attribute
{
//this is custom field given just for an example
//you can create attribute without any fields
//even an empty attribute can be used - as marker
public string Text { get; set; }
//this constructor could be used as [MethodMetadata]
public MethodMetadataAttribute ()
{
}
//This constructor could be used as [MethodMetadata("String")]
public MethodMetadataAttribute (string text)
{
Text = text;
}
}
속성 사용
[StackDemo(Text = "Hello, World!")]
public class MyClass
{
[StackDemo("Hello, World!")]
static void MyMethod()
{
}
}
속성 읽기
메서드 GetCustomAttributes
는 멤버에 적용된 사용자 지정 특성의 배열을 반환합니다. 이 배열을 검색하면 하나 이상의 특정 속성을 검색 할 수 있습니다.
var attribute = typeof(MyClass).GetCustomAttributes().OfType<MyCustomAttribute>().Single();
또는 그들을 반복합니다.
foreach(var attribute in typeof(MyClass).GetCustomAttributes()) {
Console.WriteLine(attribute.GetType());
}
System.Reflection.CustomAttributeExtensions
GetCustomAttribute
확장 메서드는 지정된 형식의 사용자 지정 특성을 검색하며 모든 MemberInfo
적용 할 수 있습니다.
var attribute = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute));
GetCustomAttribute
에는 검색 할 특성 유형을 지정하는 일반 서명이 있습니다.
var attribute = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>();
부울 인수 inherit
은 두 메소드 모두에 전달 될 수 있습니다. 이 값을 true
설정하면 요소의 조상도 검사됩니다.
DebuggerDisplay 특성
DebuggerDisplay
속성을 추가하면 DebuggerDisplay
가 마우스를 올려 놓았을 때 클래스가 표시되는 방식이 변경됩니다.
{}
로 싸인 식은 디버거에 의해 평가됩니다. 이것은 다음 샘플 또는 더 복잡한 논리와 같은 간단한 특성 일 수 있습니다.
[DebuggerDisplay("{StringProperty} - {IntProperty}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
닫는 괄호 앞에 ,nq
를 추가하면 문자열을 출력 할 때 따옴표가 제거됩니다.
[DebuggerDisplay("{StringProperty,nq} - {IntProperty}")]
{}
에 일반 표현식이 허용 되더라도 권장되지는 않습니다. DebuggerDisplay
특성은 어셈블리 메타 데이터에 문자열로 기록됩니다. {}
표현식은 유효성을 검사하지 않습니다. 그래서 좀 복잡한 논리를 포함하는 DebuggerDisplay
속성, 즉 C #에서는 제대로 작동하지만 VB.NET에서 평가 된 동일한 표현식은 구문 적으로 유효하지 않으며 디버깅하는 동안 오류가 발생합니다.
DebuggerDisplay
언어에 더 모르게 만드는 방법은 메서드 나 속성에 식을 작성하고 대신 호출하는 것입니다.
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
private string DebuggerDisplay()
{
return $"{StringProperty} - {IntProperty}"";
}
}
DebuggerDisplay
가 모든 속성 또는 일부 속성을 출력하고 객체의 유형을 디버깅하고 검사 할 때 유용합니다.
아래 예제는 DebuggerDisplay
가 디버깅 환경에서 사용되므로 #if DEBUG
로 도우미 메서드를 둘러 쌉니다.
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
#if DEBUG
private string DebuggerDisplay()
{
return
$"ObjectId:{this.ObjectId}, StringProperty:{this.StringProperty}, Type:{this.GetType()}";
}
#endif
}
발신자 정보 속성
호출자 정보 속성을 사용하여 호출자에 대한 정보를 호출 된 메소드에 전달할 수 있습니다. 선언은 다음과 같습니다.
using System.Runtime.CompilerServices;
public void LogException(Exception ex,
[CallerMemberName]string callerMemberName = "",
[CallerLineNumber]int callerLineNumber = 0,
[CallerFilePath]string callerFilePath = "")
{
//perform logging
}
호출은 다음과 같이 보입니다.
public void Save(DBContext context)
{
try
{
context.SaveChanges();
}
catch (Exception ex)
{
LogException(ex);
}
}
첫 번째 매개 변수 만 LogException
메서드에 명시 적으로 전달되는 반면 나머지는 컴파일 타임에 관련 값과 함께 제공됩니다.
callerMemberName
매개 변수는 호출 메서드의 이름 인 "Save"
값을받습니다.
callerLineNumber
매개 변수는 LogException
메서드 호출이 기록 된 행 번호를받습니다.
'callerFilePath'매개 변수는 Save
메서드가 선언 된 파일의 전체 경로를받습니다.
인터페이스에서 속성 읽기
클래스는 인터페이스의 속성을 상속하지 않으므로 인터페이스에서 속성을 얻는 간단한 방법은 없습니다. 파생 클래스에서 인터페이스를 구현하거나 멤버를 재정의 할 때마다 특성을 다시 선언해야합니다. 그래서 아래의 예에서 출력은 세 가지 경우 모두 True
입니다.
using System;
using System.Linq;
using System.Reflection;
namespace InterfaceAttributesDemo {
[AttributeUsage(AttributeTargets.Interface, Inherited = true)]
class MyCustomAttribute : Attribute {
public string Text { get; set; }
}
[MyCustomAttribute(Text = "Hello from interface attribute")]
interface IMyClass {
void MyMethod();
}
class MyClass : IMyClass {
public void MyMethod() { }
}
public class Program {
public static void Main(string[] args) {
GetInterfaceAttributeDemo();
}
private static void GetInterfaceAttributeDemo() {
var attribute1 = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute), true);
Console.WriteLine(attribute1 == null); // True
var attribute2 = typeof(MyClass).GetCustomAttributes(true).OfType<MyCustomAttribute>().SingleOrDefault();
Console.WriteLine(attribute2 == null); // True
var attribute3 = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>(true);
Console.WriteLine(attribute3 == null); // True
}
}
}
인터페이스 속성을 검색하는 한 가지 방법은 클래스가 구현 한 모든 인터페이스를 통해 인터페이스 속성을 검색하는 것입니다.
var attribute = typeof(MyClass).GetInterfaces().SelectMany(x => x.GetCustomAttributes().OfType<MyCustomAttribute>()).SingleOrDefault();
Console.WriteLine(attribute == null); // False
Console.WriteLine(attribute.Text); // Hello from interface attribute
폐기 된 속성
System.Obsolete는 더 나은 버전을 가진 형식 또는 멤버를 표시하는 데 사용되는 특성이므로 사용해서는 안됩니다.
[Obsolete("This class is obsolete. Use SomeOtherClass instead.")]
class SomeClass
{
//
}
위의 클래스를 사용하는 경우 컴파일러에서 "This class is obsolete. SomeOtherClass를 대신 사용하십시오."라는 경고를 표시합니다.