내가 인터페이스가 null을 반환 case는 null을 반환합니다.캐스트
TimesheetReminder
이 IIdentifiableEntity
인 IReminder
을 구현하지 않았다면 이해할 수 있습니다.
내가 뭘 잘못하고 있니?
내가 인터페이스가 null을 반환 case는 null을 반환합니다.캐스트
TimesheetReminder
이 IIdentifiableEntity
인 IReminder
을 구현하지 않았다면 이해할 수 있습니다.
내가 뭘 잘못하고 있니?
T
은 무엇입니까? T
이 InvoiceSummary
없는 경우 TimeSheetReminder
다음 참조 변환이 불가능하므로 IReminder<InvoiceSummary>
입니다 :
class Foo: IIdentifiableEntity { ... }
var reminder = new TimesheetReminder() as IReminder<Foo>; //returns null
봅니다 다음 ....
IReminder<InvoiceSummary> reminder = new TimesheetReminder() as IReminder<InvoiceSummary>;
난 당신이 팩토리 인스턴스를 만들 생각 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);
}
, 당신은 여전히 인터페이스를 전달하려면 (IIdentifiableEntity) 만드는 동안 팩토리 인스턴스
var factory = ReminderFactory<IIdentifiableEntity>.GetReminder("Invoicing");
솔루션 (개념 증명) : 나는 나쁜 디자인이므로 선호하지 않습니다.
우리는 인터페이스 (IReminder, IRepository) covaraint으로을 변경해야합니다.
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; }
}
그것은 코드의 마지막 줄이 기록되고 그래서'T'이 범위에 무엇을 어디 불분명 -하지만 당신에게 확인하는 방법입니다 'T'가 제공 한 구체적인 타입이 실제로는'IIdentifiableEntity' 일 때'InvoiceSummary'와 관계가없는 * 다른 * 타입보다 실제로'InvoiceSummary'가 될 것입니다. –
실제로'T'가 무엇인가에 따라'IRemainder'를'IRemainder '로 캐스팅 할 수 없습니다. 확실히 자명하다, 그렇지 않습니까? 어쩌면'T'는'InvoiceSummary'의 하위 클래스입니까? 그렇다면 귀하의 인터페이스는 동일 유형이어야합니다. –
HimBromBeere
은 어쩌면 당신은 IReminder <인보이스 요약>로 'IReminder <인보이스 요약> 알림 = 새로운 TimesheetReminder()에 의해 달성 될 수있다 필요, TimesheetReminder' 구체적으로 구현하는' '로'IReminder <인보이스 요약>'이 아닌'IReminder' –
Ferdin