2013-11-22 3 views
1

이전에 다룰 수 있었지만 좋은 해결책을 찾지 못했습니다. 이 예제에서는 반환 args 클래스와 함께 두 개의 반환 형식 클래스 (ClassA 및 ClassB)를 사용하고 있습니다. 내 ClassXml 및 ClassText에서 확장하고 인쇄의 특정 인터페이스 캐스팅을 방지하고자하는 기본 클래스가 있습니다. 이것이 가능한가?C# 반환 유형 공분산

ClassXml 및 ClassText Execute 메서드가 호출되고 해당 메서드가 적절한 인쇄를 호출하는 기본 클래스 기능을 호출합니다.

using System; 

    namespace ConsoleApplication1 
    { 
     internal class Program 
     { 
      public class ClassA 
      { 
       public string Xml 
       { 
        get { return "xml"; } 
       } 
      } 

      public class ClassB 
      { 
       public char Text 
       { 
        get { return 't'; } 
       } 
      } 

      public interface IReturnArgs<out T> 
      { 
       string Name { get; set; } 
       T Source { get; } 
      } 

      public class ReturnArgs<T> : IReturnArgs<T> 
       where T : class 
      { 
       public string Name { get; set; } 

       private T _source; 

       public T Source 
       { 
        get { return _source ?? (_source = (T) Activator.CreateInstance(typeof (T), new object[] {})); } 
       } 
      } 

      private static void Main(string[] args) 
      { 
       var classA = new ReturnArgs<ClassA>(); 
       var classB = new ReturnArgs<ClassB>(); 

       var xml = new ClassXml(); 
       xml.Execute(classA); 

       var text = new ClassText(); 
       text.Execute(classB); 

       Console.ReadKey(); 
      } 

      public abstract class ClassBase 
      { 
       public void Execute(IReturnArgs<object> args) 
       { 
        // Do something common to both classes e.g. run tasks etc (not shown) 
        // calls print when completed, each call specific to child class. 

        Print(args); 
       } 

       /// <summary> 
       /// Abstract print method. Print invokes the child implementation. 
       /// </summary> 
       /// <param name="args"></param> 
       public virtual void Print(IReturnArgs<object> args){} 
      } 

      public class ClassXml : ClassBase 
      { 
       public void Execute(IReturnArgs<ClassA> args) 
       { 
        //invoked externally (Main) calling base common functionality. 

        base.Execute(args); 

        Print(args); 
       } 

       //print invoked by child class call - Note if invoked in this class then IReturnArgs<ClassA> could be used 
       //and a cast would not be necessary - however, this would separate common calls accross child classes. 
       public void Print(IReturnArgs<ClassA> args) 
       { 
        Console.WriteLine("ClassA Source {0}", ((IReturnArgs<ClassA>)args).Source.Xml);//ugly cast 
       } 
      } 

      public class ClassText : ClassBase 
      { 
       public void Execute(IReturnArgs<ClassB> args) 
       { 
        //invoked externally (Main) calling base common functionality. 

        base.Execute(args); 
       } 

       //print invoked by base class call which requires the cast IReturnArgs<ClassB> from IReturnArgs<object> 
       public override void Print(IReturnArgs<object> args) 
       { 
        Console.WriteLine("ClassB Source {0}", ((IReturnArgs<ClassB>)args).Source.Text);//ugly cast 
       } 
      } 
     } 
    } 
+3

왜 공통 인터페이스/기본 클래스를 사용하지 않습니까? –

+0

이 예제에는 ClassBase라는 기본 클래스가 있습니다. 내가 이해하거나 해결하려고하는 것은 Child/parent 클래스간에 ReturnArgs를 전달하여 Source 속성의 다른 반환 유형을 반환하는 방법입니다. – Craig

답변

0

두 번 똑같은 일을하는 것 같습니다.

ClassAClassBClassXMLClassText과 너무 강하게 관련되어 있습니다.

ClassBClassAClassTextClassXML에서 기능을 넣을 수있는이 문제를 해결합니다.

양자 택일로, 당신은. 각각 XML 및 텍스트를 반환하는 방법 GetContent()) 당신은 단지 ITextContent.GetContent()를 호출 한 ClassContent 클래스 있어야 할 것이다이 방법을 ToString() 같은 또는 다른 인터페이스 (ITextContent를 구현할 수 있습니다.

전체 본격적인 예 :.

기본 클래스 누구의 매개 변수 유형의 자식 클래스에 의존하는 방법을 정의하지 않아야하기 때문에 당신은 정말 당신의 자식 클래스에 캐스팅의 문제에 직면해서는 안
using System; 

namespace ConsoleApplication1 
{ 
    internal class Program 
    { 
     public Interface ITextContent 
     { 
      string GetContent(); 
     } 

     public class ClassA : ITextContent 
     { 
      public string Xml 
      { 
       get { return "xml"; } 
      } 

      public string GetContent() 
      { 
       return this.Xml; 
      } 
     } 

     public class ClassB : ITextContent 
     { 
      public char Text 
      { 
       get { return 't'; } 
      } 

      public string GetContent() 
      { 
       return this.Text; 
      } 
     } 

     public interface IReturnArgs<out T> 
     { 
      string Name { get; set; } 
      T Source { get; } 
     } 

     public class ReturnArgs<T> : IReturnArgs<T> 
      where T : class 
     { 
      public string Name { get; set; } 

      private T _source; 

      public T Source 
      { 
       get { return _source ?? (_source = (T) Activator.CreateInstance(typeof (T), new object[] {})); } 
      } 
     } 

     private static void Main(string[] args) 
     { 
      var classA = new ReturnArgs<ClassA>(); 
      var classB = new ReturnArgs<ClassB>(); 

      var xml = new ClassContent(); 
      xml.Execute(classA); 

      var text = new ClassContent(); 
      text.Execute(classB); 

      Console.ReadKey(); 
     } 

     public class ClassContent 
     { 
      public void Execute(IReturnArgs<object> args) 
      { 
       Print(args); 
      } 

      public void Print(IReturnArgs<object> args) 
      { 
       Console.WriteLine(((IReturnArgs<ITextContent>)args).GetContent()); 
      } 
     } 
    } 
} 
+0

게시물 주셔서 감사합니다. ClassA와 ClassB는 T의 다른 유형을 설명하기 위해 있습니다. 하위 클래스에서 캐스팅하지 않고 기본 클래스에서 IReturnArgs 을 사용하지 않고 하위 클래스 (ClassXml, ClassText)에서 execute를 호출하려고합니다. – Craig

+0

내 대답은 여전히 ​​동일합니다. 원하는 콘텐츠를 가져 오는 ClassA 및 ClassB에 대한 공통 인터페이스를 도입함으로써 하위 수준에서 전송을 제거 할 수 있습니다. – Davio

+0

답변 해 주셔서 감사합니다. 나는 이것을 대답으로 받아 들였다. – Craig

0

기본 클래스 내가 예를 들어 ClassTextIReturnArgs<ClassA>를 사용하는 경우 수업에

ClassBase b; 
IReturnArgs<object> args; 

... 

b.Print(args); 

그러나 그것이 실패 :이없이 항상 내가 bargs에 할당 어떤 일을해서는 안 의미 모두에 공통 인터페이스이어야한다.

왜 일반베이스를 사용하지 않습니까?

public abstract class ClassBase<T> { 
    public void Execute(IReturnArgs<T> args) { ... } 
    public virtual void Print(IReturnArgs<T> args) { ... } 
} 

public class ClassXml : ClassBase<ClassA> { 
    public override void Print(IReturnArgs<ClassA> args) { 
     Console.WriteLine("ClassA Source {0}", args.Source.Text); 
    } 
} 
+0

코드를 제공해 주셔서 감사합니다. 예,이 작업은 가능하지만 유감스럽게도 기본 클래스가 제네릭이어야합니다. – Craig

+0

@ user3021646 제네릭이 될 수 없거나 없어야하는 이유가 있습니까? – nmclean