기본 인터페이스 메서드 탐구 (시행착오)

C# 8에 추가된 기본 인터페이스 메서드는 인터페이스 정의가 업데이트 됨에 따라 하위 호환을 유지하면서 기능을 확장할 수 있도록 해줍니다.

C# 8이 나올 때 기능적으로는 대략 알고는 있었지만 딱히 활용할 곳이 없어서 잊고 있다가 오늘 이렇게 활용할 수 있겠구나 싶어서 간단히 테스트 코드를 구현해보았습니다.

컨셉은, View의 object 타입의 DataContext를 기본 인터페이스 메서드를 이용해 ViewModel로 캐스팅 된 것을 바로 쓰자는 것이였는데, 결과적으로는 실패했습니다. 한번 코드를 보시죠.

var view = new SomethingView();
// view.ViewModel = new SomethingViewModel(); // ViewModel에 접근이 안됨

interface IHaveViewModel<T>
    where T : class
{
    object? DataContext { get; set; }

    public T? ViewModel { get => DataContext as T; set => DataContext = value; }
}


abstract class View
{
    public object? DataContext { get; set; }
}

class SomethingView : View, IHaveViewModel<SomethingViewModel>
{
}

class SomethingViewModel
{
    public int Value { get; set; }
}

안타깝게도? 인터페이스에서 구현된 ViewModel은 해당 인터페이스로만 접근이 되도록 제한이 되어 있습니다. 그래서 ViewModel을 호출할 수 없는데요, 이것을 굳이 캐스팅 해서 쓰자 하자면, 배보다 배꼽이 더 커집니다.

(view as IHaveViewModel<SomethingViewModel>).ViewModel = new SomethingViewModel(); // 오! 이건 아닌것 같아요

어짜피 기본 인터페이스 메서드의 기능은 인터페이스 관점에서의 유익함이기 때문에 인터페이스로만 접근되도록 한 것은 올바른 선택이긴 한 것 같습니다만… 이거 어디다가 써먹을 수 있을까요?

결국엔 중간 View 계층을 둬서 ViewModel 인스턴스에 접근이 되도록 하는게 제가 필요한 기능을 구현하는 목적에는 부합됩니다.

var view = new SomethingView();
view.ViewModel = new SomethingViewModel(); // 이렇게;;


abstract class View
{
    public object? DataContext { get; set; }
}

abstract class ExtandView<T> : View
    where T : class
{
    public T? ViewModel { get => DataContext as T; set => DataContext = value; }
}

class SomethingView : ExtandView<SomethingViewModel>
{
}

class SomethingViewModel
{
    public int Value { get; set; }
}

관련해서 좋은 아이디어나 생각 댓글로 공유 부탁해요~

좋아요 2

제가 원하는 기능을 중간 클래스를 만들지 않고 구현하는 다른 방법은 확장 메소드를 이용하는 것입니다.

var view = new SomethingView();
//view.ViewModel = new SomethingViewModel(); // 요렇게는 안되지만,
view.SetViewModel(new SomethingViewModel()); // 요렇게 설정하고
var vm = view.GetViewModel(); // 요렇게 읽을 수 있습니다.

interface IHaveViewModel<T>
    where T : class
{
    object? DataContext { get; set; }

 //   public T? ViewModel { get => DataContext as T; set => DataContext = value; }
}


abstract class View
{
    public object? DataContext { get; set; }
}

class SomethingView : View, IHaveViewModel<SomethingViewModel>
{
}

class SomethingViewModel
{
    public int Value { get; set; }
}

static class ViewExtension
{
    public static T? GetViewModel<T>(this IHaveViewModel<T> view) where T : class => view.DataContext as T;
    public static void SetViewModel<T>(this IHaveViewModel<T> view, T viewmodel) where T : class => view.DataContext = viewmodel;
}

확장메소드의 단점? 이라면 속성은 안되어서 위에 코드처럼 메소드로 표현만 가능하다는 점입니다;

좋아요 3