C #에서 사용자 지정 특성을 만드는 방법


119

여러 번 시도했지만 여전히 사용자 지정 속성의 사용법을 이해할 수 없습니다 (이미 많은 링크를 살펴 봤습니다).

누구든지 코드가있는 사용자 지정 속성의 매우 기본적인 예를 설명해 주시겠습니까?

답변:


96

사용자 지정 속성 을 만드는 코드 는 매우 간단하지만 속성이 무엇인지 이해하는 것이 매우 중요합니다.

속성은 프로그램으로 컴파일 된 메타 데이터입니다. 속성 자체는 클래스, 속성 또는 모듈에 기능을 추가하지 않고 데이터 만 추가합니다. 그러나 리플렉션을 사용하면 기능을 생성하기 위해 이러한 속성을 활용할 수 있습니다.

예를 들어 Microsoft Enterprise LibraryValidation Application Block을 살펴 보겠습니다 . 코드 예제를 보면 다음과 같이 표시됩니다.

    /// <summary>
    /// blah blah code.
    /// </summary>
    [DataMember]
    [StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"{1}\" must always have \"{4}\" characters.")]
    public string Code { get; set; }

위의 스 니펫에서 유효성 검사기의 규칙에 따라 변경 될 때마다 코드가 항상 유효성이 검사 될 것이라고 추측 할 수 있습니다 (예제에서는 8 자 이상 8 자 이하). 그러나 진실은 속성이 아무것도하지 않는다는 것입니다. 앞서 언급했듯이 속성에 메타 데이터 만 추가합니다.

그러나 엔터프라이즈 라이브러리에는 Validation.Validate개체를 조사 하는 방법이 있으며 각 속성에 대해 콘텐츠가 속성에 의해 통보 된 규칙을 위반하는지 확인합니다.

따라서 이것이 나중에 다른 메서드 / 클래스 / 등에서 사용될 수있는 코드에 데이터를 추가하는 방법 인 속성에 대해 생각해야하는 방법입니다.


내가 정말 대답을 좋아하고 특별히 ", 내가 위 코드의 set 문에 동일한 조건을 넣을 수있는 질문이 하나 더 있습니다. 그래서 속성과 어떻게 다른지,
슬래시 shogdhe

1
@slash : 다시 말해 줄 수 있나요? 나는 그 질문을 잘 이해하지 못했습니다.
Bruno Brant

1
슬래시는 속성 사용과 속성 설정자 내부에 실제 유효성 검사 코드를 넣는 것의 차이점에 대해 묻는 것을 의미한다고 생각합니다. 답변 : setter 내부에 코드를 작성하여 값의 유효성을 검사 할 수 있지만 특성 만 사용하면 유효성 검사가 수행되지 않습니다. 속성은 단지 "메타 데이터"입니다. 어딘가에있는 또 다른 코드는 사용하는 속성에 관심이 있어야하며 속성을 읽고이를 기반으로 작업을 수행해야합니다. 전형적인 예는 @BrunoBrant가 언급했듯이 유효성 검사 라이브러리입니다.
romar

10
이것이 왜 받아 들여지는 대답인지 확실하지 않습니다. 실제 질문 (Google에서도 색인이 생성됨)은 " C #에서 사용자 지정 속성 을 만드는 방법 "입니다. 대답은 그 주제를 전혀 다루지 않습니다. 반면에 두 번째 대답은 그렇습니다.
Drakestar

두 번째 대답은 질문과 더 관련이 있다고 생각합니다.
Mohammad Taherian

267

Attribute 에서 파생되는 클래스를 작성하여 시작합니다 .

public class MyCustomAttribute: Attribute
{
    public string SomeProperty { get; set; }
}

그런 다음이 속성을 사용하여 무엇이든 (클래스, 메서드, 속성 등) 장식 할 수 있습니다.

[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{

}

마지막으로 리플렉션을 사용하여 가져옵니다.

var customAttributes = (MyCustomAttribute[])typeof(Foo).GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)
{
    var myAttribute = customAttributes[0];
    string value = myAttribute.SomeProperty;
    // TODO: Do something with the value
}

AttributeUsage 속성을 사용하여이 사용자 정의 속성을 적용 할 수있는 대상 유형을 제한 할 수 있습니다 .

/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute

속성에 대해 알아야 할 중요한 사항 :

  • 속성은 메타 데이터입니다.
  • 그것들은 컴파일 타임에 어셈블리에 구워 져서 속성을 설정하는 방법에 매우 심각한 영향을 미칩니다. 상수 (컴파일 시간에 알려짐) 값만 허용됩니다.
  • 사용자 정의 속성을 이해하고 사용하는 유일한 방법은 Reflection 을 사용하는 것 입니다. 따라서 런타임에 리플렉션을 사용하여이를 가져오고 사용자 지정 특성으로 무언가를 장식하지 않으면 많은 일이 발생할 것으로 예상하지 않습니다.
  • 속성 생성 시간은 결정적이지 않습니다. CLR에 의해 인스턴스화되며 사용자는이를 제어 할 수 없습니다.

3
경우, 한 기능 / 클래스는, 나는`사용 반사 it`을 가져올 것이다
하산 유세프

@Hasan A Yousef, 예를 들어 Entity Framework에는 프레임 워크에 "키"속성이 있습니다.이 속성은 기본 키로 조정되어야합니다. ORM을 만들 때, 속성은 매우 helpfull이다
파르 사

클래스가 아닌 속성의 사용자 지정 특성에 어떻게 액세스합니까?
Canvas

docs.microsoft.com/en-us/dotnet/standard/attributes/... 단지 완성도,이 MSDN 페이지는 매우 잘 요약
바리스 Akkurt

제네릭을 사용하면 유형을 훨씬 쉽게 얻을 수 있습니다.var value = typeof(Foo).GetCustomAttributes<MyCustomAttribute>().First().SomeProperty;
jpaugh

27

Darin Dimitrov의 훌륭한 응답을 활용 / 복사 하면 다음은 클래스가 아닌 속성의 사용자 지정 속성에 액세스하는 방법입니다.

장식 된 속성 [등급 Foo] :

[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }

가져 오는 중 :

PropertyInfo propertyInfo = typeof(Foo).GetProperty(propertyToCheck);
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
if (attribute.Length > 0)
{
    MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
    string propertyValue = myAttribute.SomeProperty;
}

이것을 루프에 던지고 리플렉션을 사용 하여 class의 속성에 대한이 사용자 정의 속성에 액세스 할 수도 Foo있습니다.

foreach (PropertyInfo propertyInfo in Foo.GetType().GetProperties())
{
    string propertyName = propertyInfo.Name;

    object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
    // Just in case you have a property without this annotation
    if (attribute.Length > 0)
    {
        MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
        string propertyValue = myAttribute.SomeProperty;
        // TODO: whatever you need with this propertyValue
    }
}

고마워요, 다린 !!


속성에 어떤 유형의 속성이 존재하는지 모르는 경우 어떻게 확장 할 수 있습니까? object[] attribute = propertyInfo.GetCustomAttributes(typeof(???), true);나는 그들 모두를 반복하고 m1()각각의 알려지지 않은 속성 의 메소드 를 호출하고
싶습니다

0

짧은 대답은 C #에서 속성을 만드는 것입니다. Attribute 클래스에서 상속하면됩니다. Just this :)

하지만 여기서는 속성에 대해 자세히 설명하겠습니다.

기본적으로 속성은 어셈블리, 클래스, 메서드, 속성, 필드 등에 논리를 적용하는 데 사용할 수있는 클래스입니다.

.Net에서 Microsoft는 Obsolete 또는 ([Required], [StringLength (100)], [Range (0, 999.99)])와 같은 유효성 검사 속성과 같은 미리 정의 된 속성을 제공했으며 asp.net에는 ActionFilters와 같은 종류의 속성도 있습니다. 원하는 로직을 코드에 적용하는 데 매우 유용 할 수 있습니다 ( 배우고 싶다면 액션 필터에 대한 기사를 읽으 십시오).

서로 다른 지점에서 AttibuteUsage를 통해 속성에 일종의 구성을 적용 할 수 있습니다.

  [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]

AttributeUsage를 사용하여 특성 클래스를 장식 할 때이 특성을 사용할 위치를 C # 컴파일러에 알릴 수 있습니다. 클래스, 속성의 어셈블리 또는 ...에서이 특성을 사용할 것입니다. 정의 된 대상 (클래스, 어셈블리, 속성 등)에 대해 여러 번?!

속성에 대한이 정의 이후에 예를 보여 드리겠습니다. 대학에서 새로운 강의를 정의하고 우리 대학의 관리자와 석사 만 새로운 강의를 정의 할 수 있도록 허용한다고 가정 해 보겠습니다. Ok?

namespace ConsoleApp1
{
    /// <summary>
    /// All Roles in our scenario
    /// </summary>
    public enum UniversityRoles
    {
        Admin,
        Master,
        Employee,
        Student
    }

    /// <summary>
    /// This attribute will check the Max Length of Properties/fields
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
    public class ValidRoleForAccess : Attribute
    {
        public ValidRoleForAccess(UniversityRoles role)
        {
            Role = role;
        }
        public UniversityRoles Role { get; private set; }

    }


    /// <summary>
    /// we suppose that just admins and masters can define new Lesson
    /// </summary>
    [ValidRoleForAccess(UniversityRoles.Admin)]
    [ValidRoleForAccess(UniversityRoles.Master)]
    public class Lesson
    {
        public Lesson(int id, string name, DateTime startTime, User owner)
        {
            var lessType = typeof(Lesson);
            var validRolesForAccesses = lessType.GetCustomAttributes<ValidRoleForAccess>();

            if (validRolesForAccesses.All(x => x.Role.ToString() != owner.GetType().Name))
            {
                throw new Exception("You are not Allowed to define a new lesson");
            }
            
            Id = id;
            Name = name;
            StartTime = startTime;
            Owner = owner;
        }
        public int Id { get; private set; }
        public string Name { get; private set; }
        public DateTime StartTime { get; private set; }

        /// <summary>
        /// Owner is some one who define the lesson in university website
        /// </summary>
        public User Owner { get; private set; }

    }

    public abstract class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime DateOfBirth { get; set; }
    }


    public class Master : User
    {
        public DateTime HireDate { get; set; }
        public Decimal Salary { get; set; }
        public string Department { get; set; }
    }

    public class Student : User
    {
        public float GPA { get; set; }
    }



    class Program
    {
        static void Main(string[] args)
        {

            #region  exampl1

            var master = new Master()
            {
                Name = "Hamid Hasani",
                Id = 1,
                DateOfBirth = new DateTime(1994, 8, 15),
                Department = "Computer Engineering",
                HireDate = new DateTime(2018, 1, 1),
                Salary = 10000
            };
            var math = new Lesson(1, "Math", DateTime.Today, master);

            #endregion

            #region exampl2
            var student = new Student()
            {
                Name = "Hamid Hasani",
                Id = 1,
                DateOfBirth = new DateTime(1994, 8, 15),
                GPA = 16
            };
            var literature = new Lesson(2, "literature", DateTime.Now.AddDays(7), student);
            #endregion

            ReadLine();
        }
    }


}

프로그래밍의 실제 세계에서 우리는 속성을 사용하는 데이 접근 방식을 사용하지 않을 수 있으며 속성 사용에 대한 교육적 관점 때문에 이렇게 말했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.