0

假设我有以下接口:

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,ImageResolutionIsPretty属性。使这些实现protected以 结束CS0535,说这些属性没有实现。另一方面,制作这些public给了我CS8704,告诉我这种实现是不可能的。

除了抽象类之外,这些错误是否有解决方法?

4

2 回答 2

1

首先,你想达到什么目的?应该Foo.ReturnAs返回什么?你将如何使用这些接口?

如果不继承自 ,则不能ReturnAs在其他接口中使用IReturnableAs。一旦您从该接口继承,Foo就必须提供一个实现。当这种情况发生时,无论你如何投射Foo,你总是会得到它自己的IReturnableAs实现。

接口不是抽象类,因此只能有一个接口成员实现。您不能通过不同的接口访问不同的“默认”实现。

通过 IReturnableAs 访问时的复合结果

如果要返回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设置器,因为同一接口的有效值始终相同。

如果您想创建一个生成 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始终返回相同的值,例如"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;
  }
}

在这种情况下IReturnableAsImageIReturnableAsJson接口提供了一个实现。对于这个类:

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);
}

对于同时使用这两个接口的类,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;
}

在这种情况下,所有调用都将返回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
于 2019-09-16T10:29:04.610 回答
0

这里有一个解决方案,虽然我不确定我是否喜欢它。

IReturnableAsImage<T>并且IReturnableAsJson<T>可以用方法扩展IReturnableAs和隐藏它ReturnAsnew ReturnAs方法。

他们可以并且可能应该也显式地覆盖IReturnableAs's 的ReturnAs属性,以使 concreate 实现免于这样做;见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.ReturnAsIReturnableAsImage<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 都提供了此属性的实现。

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>)

您可能想在注释掉的行FooBar上面的行中进行注释,以查看什么时候过载以及何时过载。

例如,如果Bar显式实现ReturnAs它会覆盖两者的默认实现,IReturnableAs除非IReturnableAsImage<Bar>Bar隐式实现它们。

于 2022-02-22T21:48:40.040 回答