C#接口基础用法

时间:2016-12-17 17:03:15

标签: c# oop interface

我有基础接口:

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;

这是否可行,或者接口继承不能以这种方式工作?

4 个答案:

答案 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;
    }


}