2016-12-16 1 views
2

내가 인터페이스가 null을 반환 case는 null을 반환합니다.캐스트

TimesheetReminderIIdentifiableEntityIReminder을 구현하지 않았다면 이해할 수 있습니다.

내가 뭘 잘못하고 있니?

+3

그것은 코드의 마지막 줄이 기록되고 그래서'T'이 범위에 무엇을 어디 불분명 -하지만 당신에게 확인하는 방법입니다 'T'가 제공 한 구체적인 타입이 실제로는'IIdentifiableEntity' 일 때'InvoiceSummary'와 관계가없는 * 다른 * 타입보다 실제로'InvoiceSummary'가 될 것입니다. –

+0

실제로'T'가 무엇인가에 따라'IRemainder '를'IRemainder '로 캐스팅 할 수 없습니다. 확실히 자명하다, 그렇지 않습니까? 어쩌면'T'는'InvoiceSummary'의 하위 클래스입니까? 그렇다면 귀하의 인터페이스는 동일 유형이어야합니다. – HimBromBeere

+0

은 어쩌면 당신은 IReminder <인보이스 요약>로 'IReminder <인보이스 요약> 알림 = 새로운 TimesheetReminder()에 의해 달성 될 수있다 필요, TimesheetReminder' 구체적으로 구현하는' '로'IReminder <인보이스 요약>'이 아닌'IReminder ' – Ferdin

답변

4

T은 무엇입니까? TInvoiceSummary없는 경우 TimeSheetReminder 다음 참조 변환이 불가능하므로 IReminder<InvoiceSummary>입니다 :

class Foo: IIdentifiableEntity { ... } 
var reminder = new TimesheetReminder() as IReminder<Foo>; //returns null 
1

봅니다 다음 ....

IReminder<InvoiceSummary> reminder = new TimesheetReminder() as IReminder<InvoiceSummary>; 
0

난 당신이 팩토리 인스턴스를 만들 생각 IIdentifiableEntity를 전달하여 인터페이스는 다음과 같습니다 :

var factory = ReminderFactory<IIdentifiableEntity>.GetReminder("Invoicing"); 
항상 우리가 캐스팅 유형도 를 반환 0

reminder = new TimesheetReminder() as IReminder<T>; 

솔루션 :

팩토리 인스턴스를 만드는 동안, 우리는

인보이스 요약 구체적인 클래스 형식을 전달해야
var factory = ReminderFactory<InvoiceSummary>.GetReminder("Invoicing"); 

이메일 벤 우리가 하드 코딩 된 문자열 "인보이스"를

var factory = ReminderFactory.Create<InvoiceSummary>(); 

제거하여 공장의 인스턴스를 생성 수정할 수있는 샘플 코드는 다음과 같습니다 : 다른 이유

public class Program 
{ 
    static void Main(string[] args) 
    { 
     //Hp --> Logic: Create factory instance by passing concrete class type. 
     var factory = ReminderFactory.Create<InvoiceSummary>(); 
     var x = factory.GetRemindersToBeSent(new InvoiceRepository()); 
     x.ToList().ForEach(item => 
     Console.WriteLine($"{item.EntityName}:{item.TotalAmount}")); 

     Console.ReadKey(); 
    } 
} 

public interface IIdentifiableEntity 
{ 
    string EntityName { get; set; } 
} 

public static class ReminderFactory 
{ 
    public static IReminder<T> Create<T>() where T : IIdentifiableEntity 
    { 
     IReminder<T> reminder = null; 
     if (typeof(InvoiceSummary) == typeof(T)) 
     { 
      reminder = new TimesheetReminder() as IReminder<T>; 
     } 

     return reminder; 
    } 
} 

public interface IReminder<T> where T : IIdentifiableEntity 
{ 
    IEnumerable<T> GetRemindersToBeSent(IRepository<T> repository); 
} 

public interface IRepository<T> 
{ 
    IEnumerable<T> List { get; } 
} 

public class InvoiceRepository : IRepository<InvoiceSummary> 
{ 
    public IEnumerable<InvoiceSummary> List => new List<InvoiceSummary> { 
     new InvoiceSummary { EntityName = "Invoice", TotalAmount = 100.00M } }; 
} 

public class InvoiceSummary : IIdentifiableEntity 
{ 
    public string EntityName { get; set; } 
    public decimal TotalAmount { get; set; } 
} 

public class TimesheetReminder : IReminder<InvoiceSummary> 
{ 
    public IEnumerable<InvoiceSummary> GetRemindersToBeSent(
     IRepository<InvoiceSummary> repository) => 
     repository.List.Where(I => IsEqual("Invoice", I.EntityName)); 

    private bool IsEqual(string source, string target) => 
     string.Equals(source, target, StringComparison.CurrentCultureIgnoreCase); 
} 
0

, 당신은 여전히 ​​인터페이스를 전달하려면 (IIdentifiableEntity) 만드는 동안 팩토리 인스턴스

var factory = ReminderFactory<IIdentifiableEntity>.GetReminder("Invoicing"); 

솔루션 (개념 증명) : 나는 나쁜 디자인이므로 선호하지 않습니다.

  1. 우리는 인터페이스 (IReminder, IRepository) covaraint으로을 변경해야합니다.

  2. IIdentifiableEntity 데이터를 읽는 동안 해당하는 concreate 클래스 유형으로 캐스팅해야합니다.

샘플 코드는 다음과 같습니다 : 코드는 코멘트 따르십시오

public class Program 
{ 
    static void Main(string[] args) 
    { 
     //Hp --> Note: While creating factory instance we are passing interface type. 
     var factory = ReminderFactory<IIdentifiableEntity>.GetReminder("Invoicing"); 
     var x = factory.GetRemindersToBeSent(new InvoiceRepository()); 

     //Hp --> Note: While reading data we need to cast to corrsponding concreate class type. 
     x.Cast<InvoiceSummary>().ToList().ForEach(item => 
     Console.WriteLine($"{item.EntityName}:{item.TotalAmount}")); 
     Console.ReadKey(); 
    } 
} 

public interface IRepository<out T> 
{ 
    // Hp --> Note: You can't use setter since T it is out parameter (covariant) 
    IEnumerable<T> List { get; } 
} 

public interface IReminder<out T> where T : class, IIdentifiableEntity 
{ 
    //Hp --> Note: You can't use IRepository<T> here since T is out parameter (covariant) 
    //Instead of T use interface IIdentifiableEntity 
    IEnumerable<T> GetRemindersToBeSent(IRepository<IIdentifiableEntity> repository); 
} 

public class TimesheetReminder : IReminder<InvoiceSummary> 
{ 
    public IEnumerable<InvoiceSummary> GetRemindersToBeSent(
     //Hp --> Note: We need to cast IIdentifiableEntity to corrsponding concreate class type. 
     IRepository<IIdentifiableEntity> repository) => 
     repository.List.Where(I => IsEqual("Invoice", I.EntityName)).Cast<InvoiceSummary>(); 

    private bool IsEqual(string source, string target) => 
     string.Equals(source, target, StringComparison.CurrentCultureIgnoreCase); 
} 

public interface IIdentifiableEntity 
{ 
    string EntityName { get; set; } 
} 

public static class ReminderFactory<T> where T : class, IIdentifiableEntity 
{ 
    public static IReminder<T> GetReminder(string applicationType) 
    { 
     IReminder<T> reminder; 
     switch (applicationType) 
     { 
      case "Invoicing": 
       reminder = new TimesheetReminder() as IReminder<T>; 
       break; 
      default: 
       reminder = null; 
       break; 
     } 
     return reminder; 
    } 
} 

public class InvoiceRepository : IRepository<InvoiceSummary> 
{ 
    public IEnumerable<InvoiceSummary> List => new List<InvoiceSummary> { 
     new InvoiceSummary { EntityName = "Invoice", TotalAmount = 100.00M } }; 
} 

public class InvoiceSummary : IIdentifiableEntity 
{ 
    public string EntityName { get; set; } 
    public decimal TotalAmount { get; set; } 
}