[C#学习笔记]接口的特性与用法
视频地址:一期视频看透C#接口的全部特性及用法_哔哩哔哩_bilibili
强烈推荐学习C#和WPF的朋友关注此UP,知识点巨多,讲解透彻!
一、总览
public interface IOverall
{
/// <summary>
/// 最普通的方法
/// </summary>
void Foo();
/// <summary>
/// 属性
/// </summary>
string Name { get;set; }
/// <summary>
/// 索引器
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
int this[int index] { get; set; }
/// <summary>
/// 事件
/// </summary>
event EventHandler OnNameChanged;
/// <summary>
/// 带默认实现的方法
/// </summary>
void Bar() => Console.WriteLine("Bar");
/// <summary>
/// 私有方法(需要带默认实现)
/// </summary>
private void NonPublicMethod1() => Console.WriteLine("Private");
/// <summary>
/// 受保护方法(需要带默认实现,或者可以不实现,继承后实现)
/// </summary>
protected void NonPublicMethod2() => Console.WriteLine("Protected");
/// <summary>
/// 静态方法(需要带默认实现)
/// </summary>
static void StaticMethod() => Console.WriteLine("Static");
/// <summary>
/// 抽象静态方法
/// </summary>
static abstract void AbstractStaticMethod();
/// <summary>
/// 静态虚方法(需要带默认实现)
/// </summary>
static virtual void VirtualStaticMethod() => Console.WriteLine("Virtual Static");
}
二、带默认实现的方法
C# 8.0引入
如果接口的方法提供了一个默认实现,那么实现该接口的类可以不实现此方法。
如果实现了此方法,则会覆盖接口中的默认实现,可以理解为接口中带默认实现的方法其实是virtual,而类中的如果实现了此方法,其实是override。
2.1 用法
参考以下代码:
Test test = new Test();
((IFoo1)test).Foo1();
((IFoo1)test).Foo2();
public interface IFoo1
{
void Foo1()
{
$"这是{nameof(IFoo1)}中{nameof(Foo1)}的默认实现".Dump();
}
void Foo2()
{
$"这是{nameof(IFoo1)}中{nameof(Foo2)}的默认实现".Dump();
}
}
class Test : IFoo1
{
public void Foo1()
{
$"这是{nameof(Test)}中{nameof(Foo1)}的实际实现".Dump();
}
}
输出结果为
这是Test中Foo1的实际实现
这是IFoo1中Foo2的默认实现
对于带默认实现的方法,如果类中不实现此方法,调用时需要先将类转换成接口,再调接口上的方法,参考以下代码:
Test test = new Test();
((IFoo1)test).Foo1();
((IFoo2)test).Foo1();
public interface IFoo1
{
void Foo1()
{
$"这是{nameof(IFoo1)}中{nameof(Foo1)}的默认实现".Dump();
}
}
public interface IFoo2
{
void Foo1()
{
$"这是{nameof(IFoo2)}中{nameof(Foo1)}的默认实现".Dump();
}
}
class Test : IFoo1,IFoo2
{
}
接口IFoo1和IFoo2都有一个带默认实现的方法,且名称相同,类Test实现了IFoo1和IFoo2,如果直接能访问到接口中的方法Foo1,就会造成冲突。
2.2 应用场景
在不破坏影响已有实现的情况下,可以添加新成员。这解决了在第三方已经大量使用了的接口上进行扩展带来问题的痛点。
2.3 private,带默认实现的方法
只能在接口内调用,子接口,实现接口的类中不可访问,参考以下代码
Test test = new Test();
((IFoo1)test).Foo1();
public interface IFoo1
{
void Foo1()
{
Foo2();
}
private void Foo2()
{
$"这是{nameof(IFoo1)}中{nameof(Foo2)}的默认实现".Dump();
}
}
class Test : IFoo1
{
}
2.4 protected,带默认实现的方法
可以在子接口中调用或者覆盖,实现接口的类不可访问
参考以下代码:
Test1 test1 = new Test1();
((IFoo2)test1).Foo2();
((IFoo3)test1).Foo2();
public interface IFoo1
{
protected void Foo1()
{
$"这是{nameof(IFoo1)}中{nameof(Foo1)}的默认实现".Dump();
}
}
public interface IFoo2 : IFoo1
{
void Foo2()
{
Foo1();
}
}
public interface IFoo3 : IFoo1
{
void Foo2()
{
Foo1();
}
new void Foo1()
{
$"这是{nameof(IFoo3)}中{nameof(Foo1)}的默认实现".Dump();
}
}
class Test1:IFoo2,IFoo3
{
}
运行结果
这是IFoo1中Foo1的默认实现
这是IFoo3中Foo1的默认实现
2.5 Static,带默认实现的方法
静态方法一般用于处理泛型类
参考以下代码:
var student = IDeserializable<Student>.Deserialize("{\"Id\":42,\"Name\":\"Jack\"}");
student.Dump();
interface IDeserializable<T>
{
static T? Deserialize(string json) => JsonSerializer.Deserialize<T>(json);
}
class Student : IDeserializable<Student>
{
public int Id {get;set;}
public string Name { get; set; }
}
运行结果:
三、static abstract,抽象静态方法
在接口可不实现,实现此接口的类必须要实现此方法
应用场景:
3.1 约束子类具有方法Deserializable,实现序列化功能
interface IDeserializable<T>
{
static abstract T Deserializable(string json);
}
class MyDataModel : IDeserializable<MyDataModel>
{
public static MyDataModel Deserializable(string json)
{
return JsonSerializer.Deserialize<MyDataModel>(json);
}
}
3.2 如工厂类中具有方法Create,提供创建功能
interface IFactory<T>
{
static abstract T Create();
}
class ClassToBeCreated
{
}
class ClassWithFactoryMethod : IFactory<ClassToBeCreated>
{
public static ClassToBeCreated Create()
{
return new ClassToBeCreated();
}
}
3.3 约束子类实现静态单例
interface ISingleton<T> where T : ISingleton<T>
{
static abstract T Instance { get; }
}
class SingletonClass : ISingleton<SingletonClass>
{
private static readonly Lazy<SingletonClass> instanceHolder = new Lazy<SingletonClass>();
public static SingletonClass Instance => instanceHolder.Value;
}
3.4 逻辑运算法,提供自定义逻辑运算
interface IOperators<T> where T : IOperators<T>
{
static abstract T operator +(T left, T right);
static abstract T operator -(T left, T right);
}
class MyNumber : IOperators<MyNumber>
{
public int Value { get; }
public MyNumber(int value)
{
Value = value;
}
public static MyNumber operator +(MyNumber left, MyNumber right)
{
return new MyNumber(left.Value + right.Value);
}
public static MyNumber operator -(MyNumber left, MyNumber right)
{
return new MyNumber(left.Value - right.Value);
}
}
四、static virtual 静态虚方法
通常用于泛型调用的场合
特性:
1.子类如果未实现具体方法,调用时调用接口中的方法
2.子类如果实现具体方法,调用时调用子类中的方法
代码:
TestCallerInstance(new A());
TestCallerInstance(new B());
ITestInterfaceGenric<A>.TestCallerGeneric();
ITestInterfaceGenric<B>.TestCallerGeneric();
static void TestCallerInstance<T>(T t) where T : ITestInterface
{
Console.WriteLine(T.TestString1());
}
public interface ITestInterface
{
static virtual string TestString1()
{
return "TestString1 ITestInterface";
}
}
public interface ITestInterfaceGenric<TSelf> where TSelf : ITestInterfaceGenric<TSelf>
{
public static void TestCallerGeneric()
{
Console.WriteLine(TSelf.TestString2());
}
static virtual string TestString2()
{
return "TestString2 ITestInterfaceGeneric";
}
}
public class A : ITestInterface, ITestInterfaceGenric<A>
{
public static string TestString2()
{
return "TestString A";
}
}
public class B : ITestInterface, ITestInterfaceGenric<B>
{
public static string TestString1()
{
return "TestString1 ITestInterface B";
}
}
运行结果:
TestString1 ITestInterface
TestString1 ITestInterface B
TestString A
TestString2 ITestInterfaceGeneric