'INotifyPropertyChanged'에 해당되는 글 2건

  1. 2017.07.29 json string을 object로 역직렬화
  2. 2008.12.15 INotifyPropertyChanged 인터페이스 소개

이번 글에 대한 제목을 정하기가 어렵네요.

상황 설명을 해보자면 DB테이블에 nvarchar 타입에 json 포맷으로 된 값이 있고 이 값을 API로 전달해주면 됩니다.

리턴되는 데이터는 아래와 같습니다.


 "{ \"Key\": 1 " }"

리턴되는 타입이 string이고 그 안에 키 또는 string 값에 "문자를 필요로 하기 때문에 \문자로 string안에 string을 구분해주고 있는 것입니다.

이렇게 리턴을 하였을 경우에도 JSON.NET에서는 클래스(object)로 역직렬화가 가능합니다. 하지만 다른 언어의 다른 json 직렬화 라이브러리의 경우에는 에러가 발생하기도 하며 API 명세서에 노출하기에도 깔끔하지 못해보입니다.


최초 DB에서 받아오는 json string에 대해서 클래스(object)를 만들면 간단하게 해결됩니다. 하지만 여기서는 json string에 대한 포맷이 주기적으로 변경될 수도 있고 그에 따른 변경사항에 대해서 약결합을 만들어야 하는 상황입니다.

다음으로 생각해볼 수 있는 건 API에서 string이 아닌 타입으로 넘기면 되지 않을까 싶었고 검색을 해보았습니다.


https://stackoverflow.com/questions/22906010/deserialize-dynamic-json-string-using-newtonsoft-json-net


ExpandoObject 라는 System.Dynamic 네임스페이스의 클래스가 있었네요. JSON.NET으로 아래와 같이 역직렬화를 해주고 있습니다.


var converter = new ExpandoObjectConverter();

dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(string, converter);

=> JSON.NET에서 ExpandoObjectConverter를 제공해주고 있습니다. 해결은 아주 간단하게 되었고 ExpandoObject를 살펴보니 IDictionary<string, object>를 상속받고 있습니다. 아하~ json string을 아래처럼 Dictionary로 만들어주고 리턴을 해도 되겠군요.


Dictionary<string object> dic = new Dictionary<string object>();

dic.Add("Key", 1);

=> 그렇다면 Dictionary가 아닌 ExpandoObject 사용하는 것에 대한 장점은 무엇일까요?

1. 복잡한 json string일 경우(특히 계층 관계)

2. ExpandoObject가 INotifyPropertyChanged 인터페이스를 상속받고 있는 걸로 봐서는 프로퍼티 변경에 대한 통지(알림)를 받을 수 있네요

3. 이벤트도 추가할 수 있습니다.


해결은 간단하게 되었고 직렬화에 대한 이해도 살짝 올라갔네요. ㅎㅎ

Posted by resisa
,

INotifyPropertyChanged 인터페이스는 WPF를 하면서 처음 알게되었는데 MSDN에서 이 인터페이스에 대해서 검색을 해보면 .NET 프레임워크 2.0에서 새로 추가된 인터페이스인 것을 알 수 있다. 이 인터페이스는 그 이름대로 프로퍼티가 변경되었음을 알려주는 역할을 한다. 예제를 보기에 앞서 데이터 바인딩에 대한 간단히 알아보면 데이터 소스와 데이터가 바인딩 되는 대상이 있다. 예를 들어서 DB에 직원 정보로 가져온 데이터를 List<Employee>에 넣어 DataGridView 컨트롤에 바인딩 한다고 생각을 해보자. 여기서의 데이터 소스는 List<Employee>이고 데이터 대상은 DataGridView 컨트롤이다.

다음은 INotifyPropertyChanged 인터페이스를 상속받아서 PropertyChanged를 구현한 예이다.
public class DemoCustomer : INotifyPropertyChanged

{

    public DemoCustomer() { }

 

    private string customerName = String.Empty;

 

    public string CustomerName

    {

        get { return customerName; }

        set

        {

            customerName = value;

            OnPropertyChanged("CustomerName");

        }

    }

 

    public event PropertyChangedEventHandler PropertyChanged;

 

    protected virtual void OnPropertyChanged(String info)

    {

        if (PropertyChanged != null)

            PropertyChanged(this, new PropertyChangedEventArgs(info));

    }

}

=> 구현하는 방법은 좀 더 다양한 방법이 있지만 이 방법이 가장 심플해보이는 방법이다. 여기서 급 이번 포스트를 마무리해야 할 일이 생긴다. MSDN에 있는 예제를 실행해서 WPF가 아닌 닷넷2.0기반에서 소스를 변경하여 데이터 대상를 변경하려고 하면 PropertyChanged가 계속 null로 찍혀서 값은 변경이 되었지만 화면에는 변경이 되지 않는다.(바로 이 인터페이스의 가장 큰 역할은 소스를 변경해주면 대상에서도 자동으로 변경을 주는 것이다.) 이유를 찾기 위해서 여러가지 방법을 동원해서 알아보았지만 2.0에서는 이 인터페이스를 사용하지 말아야겠다는 결론만을 얻었다.

다음은 이 인터페이스를 구현해서 사용한 방법을 통해서 알게된 사실이다.
1. List<>를 DataGridView.DataSource 프로퍼티에 바인딩 하였을 경우에 포커스가 있는 로우의 경우에는 PropertyChaged가 null이 아니였다. 하지만 해당 로우에 포커스가 없으면 PropertyChaged가 null이고 화면에서는 변경된 사항을 알수가 없다.
2. 소스를 통해서 대상을 변경을 할 수 없다면 이 인터페이스를 사용하는 의미는 그렇게 없다고 생각이 되며 소스가 변경이 될때마다 데이터 대상에 null를 넣어주고 다시 변경된 데이터 소스를 바인딩해주는 방법을 사용하는 편이 낫다는 생각이 들었다.(List<>의 바인딩 속도는 건수가 많더라도 엄청나게 빠르다)

이번 포스트는 여러가지 테스트와 열심히 검색해봤지만 그닥 성과가 없어 상당히 아쉽다. 왜 2.0에서 INotifyPropertyChanged를 사용할 수 있게 해놓고 이런 제약조건(?)를 두어서 사용하기 힘들게 해놨는지 이해가 되지 않는다.

P.S : 제가 잘못 이해하여 오해(?)하고 있는 부분이 있다면 댓글을 통해서 알려주셨으면 합니다~

// 2009년 8월 6일
msdn 매거진에 아래와 같은 내용이 있습니다.

http://msdn.microsoft.com/ko-kr/magazine/cc794276.aspx
INotifyPropertyChanged 인터페이스를 사용할 경우 알아야 할 점이 있습니다. 이 인터페이스에 필요한 것은 PropertyChanged라는 이벤트뿐인데, 클래스가 이 이벤트를 발생시킨다는 보장이 없습니다. 많은 경우 클래스는 일부 public 속성에 대해 이벤트를 발생시키지만 아닌 경우도 있습니다. 소스 코드에 액세스할 수 없는 경우에는 PropertyChanged 이벤트를 발생시키는 속성과 그렇지 않은 속성을 미리 확인할 수 있는 마땅한 방법이 없습니다.
Posted by resisa
,