Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#接口基本用法_C#_Oop_Interface - Fatal编程技术网

C#接口基本用法

C#接口基本用法,c#,oop,interface,C#,Oop,Interface,我有基本接口: public interface IDebtBase { // with properties } 它由另一个接口继承 public interface IDebt : IDebtBase { // with properties } 另一个接口在列表中定义IDebt接口: public interface ILoanBase { List<IDebtBase> Debts { get; set; } } Loan对象实现ILoan: publ

我有基本接口:

public interface IDebtBase
{
  // with properties
}
它由另一个接口继承

public interface IDebt : IDebtBase
{
  // with properties
}
另一个接口在列表中定义IDebt接口:

public interface ILoanBase
{
     List<IDebtBase> Debts { get; set; }
}
Loan对象实现ILoan:

public class Loan : ILoan
{
    List<IDebt> Debts { get; set; }
}
我收到一个错误,指出Loan中的列表需要是IDebtBase而不是IDebt:

“Loan”未实现接口成员“ILoanBase.deborts”

这是可行的,还是接口继承不可行?

使用系统;
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; }
    }
}
使用System.Collections.Generic; 使用System.Linq; 使用系统文本; 使用System.Threading.Tasks; 命名空间控制台应用程序2 { 班级计划 { 静态void Main(字符串[]参数) { 贷款l=新贷款(); var a=1; } } 公共接口IDebtBase { //具有属性 } 公共接口IDebt:IDebtBase { //具有属性 } 公共接口ILoanBase,其中T:IDebtBase { 列表{get;set;} } 公共接口ILoan:ILoanBase { //具有属性 } 公共类贷款:伊隆 { 公共列表{get;set;} } }
我认为您试图做的是声明一个接口列表,但实际上实现了一个具体类型列表。这对于像
C.
这样的静态语言来说是很棘手的。最好的选择是对loan base接口使用泛型

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);
    }
}
现在您已将所有贷款收集到一个集合中

    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
    }
static void Main(字符串[]args)
{
列表贷款=新列表();
//填充列表
var abc=new Loan(){Issuer=“abc”,利率=22万};
abc.新增债务(10.025亿美元);
新增贷款(abc);
//迭代列表
foreach(贷款中的var贷款)
{
Console.WriteLine(贷款发行人);
foreach(贷款中的var债务。GetDebts())
{
控制台。写线(债务。金额。ToString(“C”));
}
}
//ABC
// $5,400.00
}
让我解释一下为什么这行不通

假设我添加了另一个类
Foo:IDebtBase
,然后执行

myLoan.Debts.Add(New Foo());
添加
Foo
可用于
列表(即,它可用于
ILoanBase.deberts
),但不可用于
列表(即,它不可用于
Loan.deberts


因此,如果编译器允许您以您建议的方式在
Loan
中实现
ILoanBase
,则将违反。使用泛型和泛型约束我将把泛型约束放在哪里,作为ILoan上列表的覆盖?
List
List
是不同的类型。由于IDebt继承了IDebtBase,列表债务不应该在Loan类中工作吗?不,它不工作。查找C#中的协方差和逆变换以了解一些示例。另外,请展示具体的
Debt
类实现
IDebt
。有趣的是,我会尝试一下。我担心的是我使用的是实体框架,我会混淆它。不,它应该能够处理泛型(毕竟IList是一个基于泛型的对象….IList),这很有意义,谢谢你们把它和Liskov替换原理联系起来。有趣的方法是,你们用“一旦你们开始涉及到集合,用接口构建一个层次结构树是非常棘手的。”这个方法很有意思。我将用我的应用程序来测试这个方法。
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 });
    }
}
public interface ILoanBase
{
    string Issuer { get; set; }
    IList<IDebtBase> GetDebts();
}
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
    }
myLoan.Debts.Add(New Foo());