C #에서 속성을 동적으로 추가 할 수 있습니까?


143

런타임에 속성을 추가하거나 런타임에 속성 값을 변경할 수 있습니까?

답변:


67

속성은 정적 메타 데이터입니다. 어셈블리, 모듈, 형식, 멤버, 매개 변수 및 반환 값은 C #에서 일류 개체가 아닙니다 (예 : System.Type클래스는 단순히 형식의 반영된 표현입니다). 유형에 대한 속성의 인스턴스를 가져 와서 쓰기 가능하지만 속성이 유형에 적용될 때 속성에 영향을 미치지 않는 경우 속성을 변경할 수 있습니다.


68

이것은 실제로 정확히 달성하려는 것에 달려 있습니다.

System.ComponentModel.TypeDescriptor의 물건은 종류, 특성 및 개체 인스턴스에 속성을 추가하는 데 사용, 그리고 당신이 아니라 그 속성을 검색하는 데 사용해야하는 제한이 될 수있다. 이러한 속성을 사용하는 코드를 작성하고 이러한 제한 내에서 살 수 있다면 분명히 제안 할 것입니다.

내가 아는 한 PropertyGrid 컨트롤과 Visual Studio 디자인 화면은 TypeDescriptor를 소비하는 유일한 BCL입니다. 사실, 그들이 실제로해야 할 일의 절반 정도를하는 방식입니다.


7
실제로, 대부분의 데이터 바인딩은 TypeDescriptor-뿐만 아니라 사용 PropertyGrid합니다.
Marc Gravell

1
어떤 해결 방법은 실버 라이트 프로젝트의 특성 - 메타 데이터 속성을 추가합니다 (여기서 TypeDescriptorTypeDescriptionProvider구현되지?
흔들 Weitzhandler

1
참고로 TypeDescriptor.GetAttributes ()는 중복 속성을 처리하지 않습니다. 속성 유형의 마지막 항목 만 선택합니다. Ex [Attr(1), Attr(2), Attr(3)]Attr(3)발견되었습니다.
ohmusama

11

당신은 할 수 없습니다. 한 가지 해결 방법은 런타임에 파생 클래스를 생성하고 속성을 추가하는 것일 수 있지만 약간의 과잉 일 수 있습니다.


10

글쎄, 그냥 다르기 위해 Reflection.Emit을 사용하여 참조하는 기사를 찾았습니다.

링크는 다음과 같습니다. http://www.codeproject.com/KB/cs/dotnetattributes.aspx , 가능한 접근 방식이 논의되어 있기 때문에 기사 하단의 주석 중 일부를 살펴볼 수도 있습니다.


10
Reflection.Emit 클래스를 사용하여 런타임에 속성을 만들 수 있지만 기존 속성이 아니라 Emit 패키지로 작성한 클래스에 속성을 바인딩 할 수 있습니다.
Panos

쓸모없는 대답 =)) 우리 모두는 동적 클래스가 아닌 기존 클래스에 관심을 갖습니다.
Hopeless

@Hopeless, 당신은 하위 클래스로 할 수 있습니다 YourClassYourRuntimeClassWithAttributes.
Motes

@ 무엇을 의미하는지 모릅니다. 내 클래스가 모두 미리 정의되어 있습니다. 즉, 모든 기본 클래스 (내 클래스가 상속하는)도 미리 정의 / 결정되어야합니다. Reflection.Emit을 사용하여 동적으로 생성 된 것과 관련이있는 방법을 생각할 수 없습니다.
Hopeless

1
@Hopeless, 기존 클래스에 속성을 동적으로 추가 YourClass하려면 런타임 에 속성을 서브 클래스 화하고 원하는 동적으로 생성 된 속성이있는 약간 다른 이름으로 동일한 클래스를 생성 할 수 있으며 다형성은 유형 검사 코드가 여전히 식별 할 수있게합니다 당신의 기본 클래스.
Motes

4

아뇨.

속성은 메타 데이터이며 컴파일 된 어셈블리에서 이진 형식으로 저장됩니다 (따라서 단순한 유형 만 사용할 수있는 이유도 있음).


3

나는 그렇게 믿지 않습니다. 내가 틀리더라도 희망하는 가장 좋은 것은 Type 의 인스턴스 가 아닌 전체 Type에 추가하는 것 입니다.


22
TypeDescriptor.AddAttributes (Object, Attribute [])는 클래스 수준 속성을 대상 구성 요소 인스턴스에 추가합니다.
피터 원

3

동적으로 추가 할 수있는 것이 필요한 경우 c # 속성이 적합하지 않습니다. XML로 데이터를 저장하십시오. 최근에 속성으로 시작한 프로젝트를 수행했지만 결국에는 xml로 직렬화로 이동했습니다.


1
어쩌면 그것은 아름다운 방법은 아니지만 다른 많은 라이브러리가 사용하기로 선택한 방식이며 이러한 라이브러리의 동작을 사용자 정의하려면 reflection =)) 실제로 교착 상태로 재생해야합니다.
Hopeless

3

왜 필요한가요? 속성은 리플렉션에 대한 추가 정보를 제공하지만 외부에서 원하는 속성을 알고 있으면 필요하지 않습니다.

메타 데이터를 데이터베이스 나 리소스 파일에 비교적 쉽게 외부 적으로 저장할 수 있습니다.


1
보일러 플레이트 제거. 클래스가 자동으로 클래스 내의 코드를 기반으로 속성을 생성하도록 할 수 있다면 편리하지 않습니까? SQL CLR 객체의 상용구를 줄이기 위해 이와 같은 것을 알아 내려고합니다. 볼 ... 다른 언어 쉬울 것이다 paulgraham.com/avg.html
던컨 Bayne

1

나는 System.ComponentModel.TypeDescriptor로 성공하지 않고 열심히 노력했습니다. 그것은 그것이 작동하지 않는다는 것을 의미하지는 않지만 그 코드를보고 싶습니다.

반대 부분에서는 일부 속성 값을 변경하고 싶었습니다. 나는 그 목적을 위해 잘 작동하는 2 가지 기능을 수행했습니다.

        // ************************************************************************
        public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName,  string description)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, description);
                }
            }
        }

        // ************************************************************************
        public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, isReadOnly);
                }
            }
        }

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