399

익명 형식이 인터페이스를 구현하도록 할 수 있습니까? 내가하고 싶은 코드를 가지고 있는데 어떻게해야할지 모르겠다.

두 가지 대답 중 하나를 선택하지 않았거나 인터페이스를 구현하는 클래스를 만들어 그 인스턴스를 새로 작성합니다. 이것은 실제로 이상적은 아니지만 인터페이스 상단에 얇은 동적 클래스를 만드는 메커니즘이 있는지 궁금합니다. 이렇게하면 인터페이스가 단순 해집니다.

public interface DummyInterface
{
    string A { get; }
    string B { get; }
}

public class DummySource
{
    public string A { get; set; }
    public string C { get; set; }
    public string D { get; set; }
}

public class Test
{
    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new
                     {
                         A = value.A,
                         B = value.C + "_" + value.D
                     };

        DoSomethingWithDummyInterface(values);

    }

    public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

나는 기사를 찾았다.동적 인터페이스 배치그 하나의 접근 방식을 설명합니다. 이것이 최선의 방법인가요?


7 답변


313

아니요. 익명 형식은 인터페이스를 구현할 수 없습니다. 로부터C #프로그래밍 가이드:

익명 형식은 하나 이상의 공용 읽기 전용 속성으로 구성되는 클래스 형식입니다. 메소드 나 이벤트와 같은 다른 종류의 클래스 멤버는 허용되지 않습니다. 익명 형식은 object를 제외한 모든 인터페이스 또는 형식으로 캐스팅 할 수 없습니다.


  • +1 - 익명 형식의 사용은 일반적으로 람다 및 LINQ 표현식으로 제한되어야합니다.데이터'할 일'이 필요한 발신자에게 노출되고 있습니다. 객체와 함께, 구체적인 클래스를 구현하는 것은 매우 좋은 생각입니다. - Mark
  • @ 마크 : 나는 익명의 타입을 DTO로 사용하는 것을 좋아한다. 일부 시나리오에서는 자동 매핑이 잘 작동합니다. - boj
  • 어쨌든이 물건을 가지고 있으면 좋을 것입니다. 코드 가독성에 대해 이야기하고 있다면 람다 식은 일반적으로 사용할 수있는 방법이 아닙니다. RAD에 대해 이야기 할 경우 Java와 유사한 익명 인터페이스 구현으로 들어갑니다. 그건 그렇고, 어떤 경우에는 그 기능이 대리인보다 더 강력합니다 - Arsen Zahray
  • @ArsenZahray : lambda 표현식을 사용하면 코드 가독성이 향상됩니다. 기능 체인에 사용될 때 특히 강력합니다. 이로 인해 지역 변수의 필요성이 줄어들거나 제거 될 수 있습니다. - Roy Tinker
  • @DmitryPavlov, 그것은 놀랍게도 귀중했습니다. Passersby :이리응축 된 버전입니다. - kdbanman

82

이 질문은 2 년 된 질문 일 수 있지만 스레드의 답변이 모두 사실 일지라도 나는 사실 그것이 사실이라고 말할 수있는 충고에 저항 할 수 없습니다.가능하다익명의 클래스가 인터페이스를 구현하도록하는 것은 비록 약간의 창조적 인 부정 행위가 거기에 도착하기는하지만 말입니다.

2008 년에 나는 그 당시의 고용주를 위해 맞춤 LINQ 제공 업체를 작성하고 있었고 어느 시점에서 다른 익명 사용자로부터 "내"익명 클래스를 말할 수 있어야했습니다. 이는 입력 확인에 사용할 수있는 인터페이스를 구현해야한다는 의미였습니다. 그들. 우리가 해결 한 방법은 (우리가 사용한포스트 샤프)를 사용하여 인터페이스 구현을 IL에 직접 추가 할 수 있습니다. 사실,익명 클래스가 인터페이스를 구현하도록 허용, 규칙을 약간 구부려서 거기에 도착하면됩니다.


  • 이것은 내가 적극적으로 피하는 행동의 일종입니다. 다른 컴퓨터에서 컴파일하면 모든 것이 터집니다. - Gusdor
  • 나는 규칙 부분을 굽히는 것을 좋아한다;) - Beatles1692
  • @Gusdor는이 경우 빌드를 완벽하게 제어 할 수 있었으며 항상 전용 시스템에서 실행되었습니다. 또한 PostSharp를 사용하고 있었기 때문에 우리가하고 있던 일은 그 프레임 워크 내에서 완전히 합법적이었습니다. PostSharp가 우리가 사용하고 있던 빌드 서버에 설치되어있는 한 실제로 어떤 것도 튀어 나올 수 없었습니다. - Mia Clarke
  • @Gusdor 나는 다른 프로그래머가 프로젝트를 얻고 어려움없이 컴파일하는 것이 쉬워야한다는 데 동의하지만, 이는 포스트 샤프와 같은 도구 또는 프레임 워크를 완전히 피하지 않고도 별도로 해결할 수있는 다른 문제입니다. 동일한 주장은 VS 자체 또는 C #스펙의 일부가 아닌 다른 비표준 MS 프레임 워크에 대해 만들어 질 수 있습니다. 그런 것들이 필요하거나 그렇지 않으면 " 팝 팝 " IMO에는 문제가 없습니다. 문제는 빌드가 너무 복잡하여 모든 작업을 올바르게 처리하기가 어려울 때입니다. - AaronLS
  • @ZainRizvi 아니, 그럴 수 없었다. 내가 아는 한, 아직 생산 중에 있습니다. 제기 된 관심사는 저에게 이상하고, 지금 나에게 최선을 다하는 것처럼 보였습니다. 기본적으로 " 프레임 워크를 사용하지 마세요, 모든 일이 중단됩니다 "라고 말하고 있습니다. 그들은 팝업되지 않았으며 놀라지 않을 것입니다. - Mia Clarke

41

익명 형식을 인터페이스에 캐스팅하는 것은 내가 잠시 동안 원했던 것이지만 불행히도 현재 구현에서는 해당 인터페이스를 구현해야합니다.

그 주위의 최상의 솔루션은 구현을 생성하는 동적 프록시의 일부 유형을 갖는 것입니다. 우수한 것을 사용함LinFu 프로젝트너 대체 할 수있어.

select new
{
  A = value.A,
  B = value.C + "_" + value.D
};

 select new DynamicObject(new
 {
   A = value.A,
   B = value.C + "_" + value.D
 }).CreateDuck<DummyInterface>();


  • Impromptu-Interface ProjectDLR을 사용하는 .NET 4.0에서이 작업을 수행 할 것이고 Linfu는 더 가볍습니다. - jbtule
  • ~이다.DynamicObjectLinFu 유형?System.Dynamic.DynamicObject보호 된 생성자 만 있습니다 (.NET 4.5 이상). - jdmcnair
  • 예. 나는 LinFu 구현을 언급했다.DynamicObjectDLR 버전 이전 - Arne Claassen

12

아니; 익명 형식은 몇 가지 속성을 제외하고는 아무 것도 할 수 없습니다. 자신 만의 유형을 만들어야합니다. 나는 링크 된 기사를 깊이 읽지는 않았지만 Reflection.Emit을 사용하여 새로운 유형을 즉석에서 생성하는 것처럼 보입니다. 그러나 토론을 사물에 한정한다면C #내에서당신은 당신이 원하는 것을 할 수 없습니다.


  • 주목할만한 점은 속성에 함수 또는 공백 (액션)도 포함될 수 있습니다. 새 {{MyFunction = new Func < string, bool > (s = > value.A == s)}는 (value.A 대신 'A'를 사용할 수 없음). - cfeduke
  • 음, 대리인 일 뿐이 아닌가? 실제로는 방법이 아닙니다. - Marc Gravell
  • Reflection.Emit을 사용하여 런타임에 유형을 만들었지 만 런타임 비용을 피하기 위해 AOP 솔루션을 선호한다고 생각합니다. - Norman H

12

익명 형식은 동적 프록시를 통해 인터페이스를 구현할 수 있습니다.

나는에 확장 방법을 썼다.GitHub블로그 게시물http://wblo.gs/feE이 시나리오를 지원합니다.

이 메서드는 다음과 같이 사용할 수 있습니다.

class Program
{
    static void Main(string[] args)
    {
        var developer = new { Name = "Jason Bowers" };

        PrintDeveloperName(developer.DuckCast<IDeveloper>());

        Console.ReadKey();
    }

    private static void PrintDeveloperName(IDeveloper developer)
    {
        Console.WriteLine(developer.Name);
    }
}

public interface IDeveloper
{
    string Name { get; }
}


11

가장 좋은 해결책은 익명의 클래스를 사용하지 않는 것입니다.

public class Test
{
    class DummyInterfaceImplementor : IDummyInterface
    {
        public string A { get; set; }
        public string B { get; set; }
    }

    public void WillThisWork()
    {
        var source = new DummySource[0];
        var values = from value in source
                     select new DummyInterfaceImplementor()
                     {
                         A = value.A,
                         B = value.C + "_" + value.D
                     };

        DoSomethingWithDummyInterface(values.Cast<IDummyInterface>());

    }

    public void DoSomethingWithDummyInterface(IEnumerable<IDummyInterface> values)
    {
        foreach (var value in values)
        {
            Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
        }
    }
}

쿼리의 결과를 인터페이스 유형으로 변환해야합니다. 더 좋은 방법이있을 수도 있지만 찾을 수는 없습니다.


  • 너는 사용할 수있어.values.OfType<IDummyInterface>()던지기 대신에. 이 컬렉션은 실제로 해당 유형으로 캐스팅 할 수있는 객체 만 반환합니다. 그것은 모두 당신이 원하는 것에 달려 있습니다. - Kristoffer L

7

구체적으로 묻는 질문에 대한 대답은 아니오입니다. 그러나 조롱 한 프레임 워크를 보셨습니까? MOQ를 사용하지만 거기에는 수백만 가지가 있으며 인라인으로 / 스텁 (부분적으로 또는 완전히) 인터페이스를 구현할 수 있습니다. 예 :

public void ThisWillWork()
{
    var source = new DummySource[0];
    var mock = new Mock<DummyInterface>();

    mock.SetupProperty(m => m.A, source.Select(s => s.A));
    mock.SetupProperty(m => m.B, source.Select(s => s.C + "_" + s.D));

    DoSomethingWithDummyInterface(mock.Object);
}

연결된 질문


최근 질문