C#8.0:具有默认实现的接口的受保护属性
C#8.0: Protected properties for interfaces with default implementations
假设我有以下接口:
public interface IReturnableAs {
protected String ReturnAs { get; set; }
}
public interface IReturnableAsImage<T> {
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large") {
ReturnAs = "image";
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T> {
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
ReturnAs = "json";
IsPretty = isPretty;
return (T)this;
}
}
public class Foo : IReturnableAsImage<Foo>, IReturnableAsJson<Foo> {...}
最初,这些错误迫使我实现 ReturnAs
、ImageResolution
和 IsPretty
属性。使这些实现 protected
以 CS0535
结束,表示属性未实现。另一方面,制作这些 public
给了我 CS8704
,告诉我这个实现是不可能的。
除了抽象 类,这些错误是否有解决方法?
首先,你想达到什么目的?什么应该Foo.ReturnAs
return?您将如何使用这些界面?
如果不继承IReturnableAs
,则不能在其他接口中使用ReturnAs
。一旦您从该接口继承,尽管 Foo
将必须提供一个实现。发生这种情况时,无论您如何转换 Foo
,您总是会得到它自己的 IReturnableAs
实现。
接口不是抽象的 class 因此只能有 一个 接口成员实现。您不能通过不同的接口访问不同的 "default" 实现。
通过 IReturnableAs 访问时的复合结果
如果您想要 return json
或 image
用于特定接口,image;json
用于 Foo
总体而言,最好的选择是接口不继承自IReturnableAs
,并提供自己的ReturnAs
属性 :
public interface IReturnableAs {
public String ReturnAs { get; }
}
public interface IReturnableAsImage<T>
{
public String ReturnAs =>"image";
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large")
{
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T> {
public String ReturnAs =>"json";
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
IsPretty = isPretty;
return (T)this;
}
}
public class Foo : IReturnableAsImage<Foo>, IReturnableAsJson<Foo> ,IReturnableAs
{
string IReturnableAs.ReturnAs =>"image;json";
String IReturnableAsImage<Foo>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<Foo>.IsPretty { get; set; }=false;
}
以下代码:
void Main()
{
var foo=new Foo();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<Foo>)foo).ReturnAs);
Console.WriteLine(((IReturnableAsJson<Foo>)foo).ReturnAs);
}
打印:
image;json
image
json
我删除了 ReturnAs
设置器,因为同一接口的有效值将始终相同。
如果您想创建一个新的 class 生成 JPG,例如 FooJpg
,您可以覆盖 IReturnableAsImage<T>
的默认实现,例如:
public class FooJpg : IReturnableAsImage<FooJpg>, IReturnableAsJson<FooJpg> ,IReturnableAs
{
string IReturnableAs.ReturnAs =>"jpg;json";
String IReturnableAsImage<FooJpg>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<FooJpg>.IsPretty { get; set; }=false;
String IReturnableAsImage<FooJpg>.ReturnAs => "jpg";
}
无论界面如何,结果都一样
如果您希望 Foo.ReturnAs
始终 return 相同的值,例如 "image;json"
,您可以为单个用例添加默认的 IReturnAs
实现,并覆盖多种用途的方法:
public interface IReturnableAs {
public String ReturnAs { get; }
}
public interface IReturnableAsImage<T>:IReturnableAs
{
String IReturnableAs.ReturnAs =>"image";
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large")
{
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T>:IReturnableAs {
String IReturnableAs.ReturnAs =>"json";
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
//ReturnAs="json";
IsPretty = isPretty;
return (T)this;
}
}
在这种情况下,IReturnableAsImage
、IReturnableAsJson
接口提供了一个实现。为此 class :
public class Foo : IReturnableAsImage<Foo>
{
String IReturnableAsImage<Foo>.ImageResolution { get; set; }="3";
}
以下代码将打印 image
:
void Main()
{
var foo=new Foo();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<Foo>)foo).ReturnAs);
}
对于使用两个接口的 class,需要显式 IReturnableAs
实现:
public class FooMulti : IReturnableAsImage<FooMulti>, IReturnableAsJson<FooMulti>
{
String IReturnableAs.ReturnAs =>"image;json";
String IReturnableAsImage<FooMulti>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<FooMulti>.IsPretty { get; set; }=false;
}
在这种情况下,所有调用都将 return image;json
:
void Main()
{
var foo=new FooMulti();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<FooMulti>)foo).ReturnAs);
Console.WriteLine(((IReturnableAsJson<FooMulti>)foo).ReturnAs);
}
image;json
image;json
image;json
这里有一个解决方案,虽然我不确定我是否喜欢它。
IReturnableAsImage<T>
和 IReturnableAsJson<T>
可以扩展 IReturnableAs
并使用 new
ReturnAs
方法隐藏其 ReturnAs
方法。
他们可以,而且可能应该,也明确地覆盖 IReturnableAs
的 ReturnAs
属性 来避免必须这样做的具体实现;请参阅下面 Bar
的实施。
尽管 Foo
同时实现了 IReturnableAsImage<T>
和 IReturnableAsJson<T>
,它也必须为 IReturnableAs.ReturnAs
提供实现。
public interface IReturnableAs
{
public String ReturnAs { get; }
}
public interface IReturnableAsImage<T> : IReturnableAs
{
// implicitly "override" IReturnableAs's ReturnAs
string IReturnableAs.ReturnAs => ReturnAs;
// use "new" to indicate hiding on purpose
public new string ReturnAs => "image";
protected string ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large")
{
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T> : IReturnableAs
{
// implicitly "override" IReturnableAs's ReturnAs
string IReturnableAs.ReturnAs => ReturnAs;
// use "new" to indicate hiding on purpose
public new string ReturnAs => "json";
protected bool IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false)
{
isPretty = isPretty;
return (T)this;
}
}
Bar
不需要实施 IReturnableAs.ReturnAs
因为 IReturnableAsImage<Bar>
已经这样做了。虽然它可能会“过载”(重新实现可能是一个更好的术语)隐式地 ReturnAs
或显式地 IReturnableAs.ReturnAs
或 IReturnableAsImage<Bar>.ReturnAs
,以任何组合。
public class Bar : IReturnableAsImage<Bar>
{
// public string ReturnAs => "implicit ReturnAs";
// string IReturnableAs.ReturnAs => "explicit IReturnableAs.ReturnAs";
// string IReturnableAsImage<Bar>.ReturnAs => "explicit IReturnableAsImage<Bar>.ReturnAs";
string IReturnableAsImage<Bar>.ImageResolution { get; set; } = "3";
}
另一方面,Foo
必须明确地重新实现 IReturnableAs.ReturnAs
隐式或 ReturnAs
显式(或两者),因为 IReturnableAsImage 和 IReturnableAsJson 都为此 属性 提供了实现。 =44=]
public class Foo : IReturnableAsImage<Foo>, IReturnableAsJson<Foo>
{
// public string ReturnAs => "implicit";
// string IReturnableAsImage<Bar>.ReturnAs => "explicit image";
// string IReturnableAsJson<Bar>.ReturnAs => "explicit json";
string IReturnableAs.ReturnAs => "image;json";
string IReturnableAsImage<Foo>.ImageResolution { get; set; } = "3";
bool IReturnableAsJson<Foo>.IsPretty { get; set; } = false;
}
结果按预期工作,但改变重新实现的具体方法会改变结果,这可能出乎意料。
void Main()
{
var bar = new Bar();
Console.WriteLine("Bar: ");
Console.WriteLine(((IReturnableAs)bar).ReturnAs + " - (IReturnableAs)" );
Console.WriteLine(((IReturnableAsImage<Bar>)bar).ReturnAs + " -
(IReturnableAsImage<Bar>)");
// only works when ReturnAs is explicitly implemented on Bar
// Console.WriteLine(bar.ReturnAs + " - (Bar)");
Console.WriteLine();
var foo = new Foo();
Console.WriteLine("Foo:");
Console.WriteLine(((IReturnableAs)foo).ReturnAs + " - (IReturnableAs)");
Console.WriteLine(((IReturnableAsImage<Foo>)foo).ReturnAs + " - (IReturnableAsImage<Foo>)");
Console.WriteLine(((IReturnableAsJson<Foo>)foo).ReturnAs + " - (IReturnableAsJson<Foo>)");
// only works when ReturnAs is explicitly implemented on Foo
// Console.WriteLine(foo.ReturnAs + " - (Foo)");
}
输出:
Bar:
image - (IReturnableAs)
image - (IReturnableAsImage<Bar>)
Foo:
image;json - (IReturnableAs)
image - (IReturnableAsImage<Foo>)
json - (IReturnableAsJson<Foo>)
您可能想在上面 Foo
和 Bar
的注释掉的行中发表评论,以查看过载的内容和时间。
例如,如果 Bar
显式实现 ReturnAs
,它将覆盖 IReturnableAs
和 IReturnableAsImage<Bar>
的默认实现,除非 Bar
也隐式实现它们。
假设我有以下接口:
public interface IReturnableAs {
protected String ReturnAs { get; set; }
}
public interface IReturnableAsImage<T> {
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large") {
ReturnAs = "image";
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T> {
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
ReturnAs = "json";
IsPretty = isPretty;
return (T)this;
}
}
public class Foo : IReturnableAsImage<Foo>, IReturnableAsJson<Foo> {...}
最初,这些错误迫使我实现 ReturnAs
、ImageResolution
和 IsPretty
属性。使这些实现 protected
以 CS0535
结束,表示属性未实现。另一方面,制作这些 public
给了我 CS8704
,告诉我这个实现是不可能的。
除了抽象 类,这些错误是否有解决方法?
首先,你想达到什么目的?什么应该Foo.ReturnAs
return?您将如何使用这些界面?
如果不继承IReturnableAs
,则不能在其他接口中使用ReturnAs
。一旦您从该接口继承,尽管 Foo
将必须提供一个实现。发生这种情况时,无论您如何转换 Foo
,您总是会得到它自己的 IReturnableAs
实现。
接口不是抽象的 class 因此只能有 一个 接口成员实现。您不能通过不同的接口访问不同的 "default" 实现。
通过 IReturnableAs 访问时的复合结果
如果您想要 return json
或 image
用于特定接口,image;json
用于 Foo
总体而言,最好的选择是接口不继承自IReturnableAs
,并提供自己的ReturnAs
属性 :
public interface IReturnableAs {
public String ReturnAs { get; }
}
public interface IReturnableAsImage<T>
{
public String ReturnAs =>"image";
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large")
{
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T> {
public String ReturnAs =>"json";
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
IsPretty = isPretty;
return (T)this;
}
}
public class Foo : IReturnableAsImage<Foo>, IReturnableAsJson<Foo> ,IReturnableAs
{
string IReturnableAs.ReturnAs =>"image;json";
String IReturnableAsImage<Foo>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<Foo>.IsPretty { get; set; }=false;
}
以下代码:
void Main()
{
var foo=new Foo();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<Foo>)foo).ReturnAs);
Console.WriteLine(((IReturnableAsJson<Foo>)foo).ReturnAs);
}
打印:
image;json
image
json
我删除了 ReturnAs
设置器,因为同一接口的有效值将始终相同。
如果您想创建一个新的 class 生成 JPG,例如 FooJpg
,您可以覆盖 IReturnableAsImage<T>
的默认实现,例如:
public class FooJpg : IReturnableAsImage<FooJpg>, IReturnableAsJson<FooJpg> ,IReturnableAs
{
string IReturnableAs.ReturnAs =>"jpg;json";
String IReturnableAsImage<FooJpg>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<FooJpg>.IsPretty { get; set; }=false;
String IReturnableAsImage<FooJpg>.ReturnAs => "jpg";
}
无论界面如何,结果都一样
如果您希望 Foo.ReturnAs
始终 return 相同的值,例如 "image;json"
,您可以为单个用例添加默认的 IReturnAs
实现,并覆盖多种用途的方法:
public interface IReturnableAs {
public String ReturnAs { get; }
}
public interface IReturnableAsImage<T>:IReturnableAs
{
String IReturnableAs.ReturnAs =>"image";
protected String ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large")
{
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T>:IReturnableAs {
String IReturnableAs.ReturnAs =>"json";
protected Boolean IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false) {
//ReturnAs="json";
IsPretty = isPretty;
return (T)this;
}
}
在这种情况下,IReturnableAsImage
、IReturnableAsJson
接口提供了一个实现。为此 class :
public class Foo : IReturnableAsImage<Foo>
{
String IReturnableAsImage<Foo>.ImageResolution { get; set; }="3";
}
以下代码将打印 image
:
void Main()
{
var foo=new Foo();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<Foo>)foo).ReturnAs);
}
对于使用两个接口的 class,需要显式 IReturnableAs
实现:
public class FooMulti : IReturnableAsImage<FooMulti>, IReturnableAsJson<FooMulti>
{
String IReturnableAs.ReturnAs =>"image;json";
String IReturnableAsImage<FooMulti>.ImageResolution { get; set; }="3";
Boolean IReturnableAsJson<FooMulti>.IsPretty { get; set; }=false;
}
在这种情况下,所有调用都将 return image;json
:
void Main()
{
var foo=new FooMulti();
Console.WriteLine(((IReturnableAs)foo).ReturnAs);
Console.WriteLine(((IReturnableAsImage<FooMulti>)foo).ReturnAs);
Console.WriteLine(((IReturnableAsJson<FooMulti>)foo).ReturnAs);
}
image;json
image;json
image;json
这里有一个解决方案,虽然我不确定我是否喜欢它。
IReturnableAsImage<T>
和 IReturnableAsJson<T>
可以扩展 IReturnableAs
并使用 new
ReturnAs
方法隐藏其 ReturnAs
方法。
他们可以,而且可能应该,也明确地覆盖 IReturnableAs
的 ReturnAs
属性 来避免必须这样做的具体实现;请参阅下面 Bar
的实施。
尽管 Foo
同时实现了 IReturnableAsImage<T>
和 IReturnableAsJson<T>
,它也必须为 IReturnableAs.ReturnAs
提供实现。
public interface IReturnableAs
{
public String ReturnAs { get; }
}
public interface IReturnableAsImage<T> : IReturnableAs
{
// implicitly "override" IReturnableAs's ReturnAs
string IReturnableAs.ReturnAs => ReturnAs;
// use "new" to indicate hiding on purpose
public new string ReturnAs => "image";
protected string ImageResolution { get; set; }
public T ReturnAsImage(String imageResolution = "large")
{
ImageResolution = imageResolution;
return (T)this;
}
}
public interface IReturnableAsJson<T> : IReturnableAs
{
// implicitly "override" IReturnableAs's ReturnAs
string IReturnableAs.ReturnAs => ReturnAs;
// use "new" to indicate hiding on purpose
public new string ReturnAs => "json";
protected bool IsPretty { get; set; }
public T ReturnAsJson(Boolean isPretty = false)
{
isPretty = isPretty;
return (T)this;
}
}
Bar
不需要实施 IReturnableAs.ReturnAs
因为 IReturnableAsImage<Bar>
已经这样做了。虽然它可能会“过载”(重新实现可能是一个更好的术语)隐式地 ReturnAs
或显式地 IReturnableAs.ReturnAs
或 IReturnableAsImage<Bar>.ReturnAs
,以任何组合。
public class Bar : IReturnableAsImage<Bar>
{
// public string ReturnAs => "implicit ReturnAs";
// string IReturnableAs.ReturnAs => "explicit IReturnableAs.ReturnAs";
// string IReturnableAsImage<Bar>.ReturnAs => "explicit IReturnableAsImage<Bar>.ReturnAs";
string IReturnableAsImage<Bar>.ImageResolution { get; set; } = "3";
}
另一方面,Foo
必须明确地重新实现 IReturnableAs.ReturnAs
隐式或 ReturnAs
显式(或两者),因为 IReturnableAsImage 和 IReturnableAsJson 都为此 属性 提供了实现。 =44=]
public class Foo : IReturnableAsImage<Foo>, IReturnableAsJson<Foo>
{
// public string ReturnAs => "implicit";
// string IReturnableAsImage<Bar>.ReturnAs => "explicit image";
// string IReturnableAsJson<Bar>.ReturnAs => "explicit json";
string IReturnableAs.ReturnAs => "image;json";
string IReturnableAsImage<Foo>.ImageResolution { get; set; } = "3";
bool IReturnableAsJson<Foo>.IsPretty { get; set; } = false;
}
结果按预期工作,但改变重新实现的具体方法会改变结果,这可能出乎意料。
void Main()
{
var bar = new Bar();
Console.WriteLine("Bar: ");
Console.WriteLine(((IReturnableAs)bar).ReturnAs + " - (IReturnableAs)" );
Console.WriteLine(((IReturnableAsImage<Bar>)bar).ReturnAs + " -
(IReturnableAsImage<Bar>)");
// only works when ReturnAs is explicitly implemented on Bar
// Console.WriteLine(bar.ReturnAs + " - (Bar)");
Console.WriteLine();
var foo = new Foo();
Console.WriteLine("Foo:");
Console.WriteLine(((IReturnableAs)foo).ReturnAs + " - (IReturnableAs)");
Console.WriteLine(((IReturnableAsImage<Foo>)foo).ReturnAs + " - (IReturnableAsImage<Foo>)");
Console.WriteLine(((IReturnableAsJson<Foo>)foo).ReturnAs + " - (IReturnableAsJson<Foo>)");
// only works when ReturnAs is explicitly implemented on Foo
// Console.WriteLine(foo.ReturnAs + " - (Foo)");
}
输出:
Bar:
image - (IReturnableAs)
image - (IReturnableAsImage<Bar>)
Foo:
image;json - (IReturnableAs)
image - (IReturnableAsImage<Foo>)
json - (IReturnableAsJson<Foo>)
您可能想在上面 Foo
和 Bar
的注释掉的行中发表评论,以查看过载的内容和时间。
例如,如果 Bar
显式实现 ReturnAs
,它将覆盖 IReturnableAs
和 IReturnableAsImage<Bar>
的默认实现,除非 Bar
也隐式实现它们。