我有基础接口:
public interface IDebtBase
{
// with properties
}
由另一个接口继承
public interface IDebt : IDebtBase
{
// with properties
}
另一个接口在列表中定义IDebt接口:
public interface ILoanBase
{
List<IDebtBase> Debts { get; set; }
}
是为另一个接口ILoan继承的:
public interface ILoan : ILoanBase
{
// with properties
}
Loan对象实现了ILoan:
public class Loan : ILoan
{
List<IDebt> Debts { get; set; }
}
作为完整参考,Debt对象实现了IDebt:
public class Debt : IDebt
{
// with properties
}
我收到一条错误消息,指出贷款中的列表需要是IDebtBase而不是IDebt:
&#39;贷款&#39;没有实现接口成员&#39; ILoanBase.Debts&#39;
这是否可行,或者接口继承不能以这种方式工作?
答案 0 :(得分:1)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Loan l = new Loan();
var a = 1;
}
}
public interface IDebtBase
{
// with properties
}
public interface IDebt : IDebtBase
{
// with properties
}
public interface ILoanBase<T> where T : IDebtBase
{
List<T> Debts { get; set; }
}
public interface ILoan : ILoanBase<IDebt>
{
// with properties
}
public class Loan : ILoan
{
public List<IDebt> Debts { get; set; }
}
}
答案 1 :(得分:1)
我认为你要做的是声明一个接口列表,但实际上实现了一个具体类型列表。这对于像C#
这样的静态语言来说很棘手。您最好的选择是使用泛型作为贷款基础界面。
public interface IDebtBase
{
decimal Amount { get; set; }
}
public interface IDebt : IDebtBase
{
int ID { get; set; }
}
public interface ILoanBase<TDebt> where TDebt : IDebtBase
{
List<TDebt> Debts { get; set; }
}
public interface ILoan : ILoanBase<IDebt>
{
decimal Rate { get; set; }
}
public class Debt : IDebt
{
public int ID { get; set; }
public decimal Amount { get; set; }
}
public class Loan : ILoan
{
public static decimal DefaultRate=0.18m;
public Loan()
{
this.Debts=new List<IDebt>();
this.Rate=DefaultRate;
}
public List<IDebt> Debts { get; set; }
public decimal Rate { get; set; }
public void AddDebt(int id, decimal amount)
{
Debts.Add(new Debt() { ID=id, Amount=amount });
}
}
class Program
{
static void Main(string[] args)
{
var loan=new Loan() { Rate=0.22m };
loan.AddDebt(1002, 5400m);
}
}
缺点是并非所有贷款都来自一种类型。这是因为ILoadBase<IDebt>
与ILoadBase<IDebtBase>
不同。根据我的经验,一旦开始涉及集合,使用接口构建层次结构树非常棘手。
上述的替代方法是更改贷款类型以使用具体债务类
public interface ILoan : ILoanBase<Debt> // change from ILoanBase<IDebt>
{
decimal Rate { get; set; }
}
public class Loan : ILoan
{
public static decimal DefaultRate=0.18m;
public Loan()
{
this.Debts=new List<Debt>(); // change from List<IDebt>
this.Rate=DefaultRate;
}
public List<Debt> Debts { get; set; } // Change from List<IDebt>
public decimal Rate { get; set; }
public void AddDebt(int id, decimal amount)
{
Debts.Add(new Debt() { ID=id, Amount=amount });
}
}
最后会给你一个List<Debt>
集合(我认为这是你想要的)。现在,为了使它更有用,创建一个没有泛型的公共基础贷款类
public interface ILoanBase
{
string Issuer { get; set; }
IList<IDebtBase> GetDebts();
}
并将其用于每个贷款界面。最后在具体的贷款类中,您需要实施GetDebts()
,将List<Debt>
转换为List<IDebtBase>
。
public interface ILoanBase<TDebt> : ILoanBase
where TDebt : IDebtBase
{
List<TDebt> Debts { get; set; }
}
public class Loan : ILoan
{
...
public IList<IDebtBase> GetDebts()
{
return Debts.OfType<IDebtBase>().ToList();
}
}
现在您已将所有贷款收集到一个集合中
static void Main(string[] args)
{
List<ILoanBase> loans=new List<ILoanBase>();
//populate list
var abc=new Loan() { Issuer="ABC", Rate=0.22m };
abc.AddDebt(1002, 5400m);
loans.Add(abc);
//iterate list
foreach (var loan in loans)
{
Console.WriteLine(loan.Issuer);
foreach (var debt in loan.GetDebts())
{
Console.WriteLine(debt.Amount.ToString("C"));
}
}
// ABC
// $5,400.00
}
答案 2 :(得分:1)
让我解释为什么这不会起作用。
假设我添加了另一个类Foo : IDebtBase
并执行
myLoan.Debts.Add(New Foo());
在Foo
上添加List<IDebtBase>
作品(即,它适用于ILoanBase.Debts
),而不是List<IDebt>
上的作品(即,它不会工作)在Loan.Debts
)。
因此,如果编译器允许您按照提议的方式在ILoanBase
中实现Loan
,则会违反Liskov substitution principle。
答案 3 :(得分:-2)
需要明确的界面分配尝试这样写
public class Loan : ILoan
{
List<IDebtBase> ILoanBase.Debts
{
get;set;
}
}