Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.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#new关键字来扩展接口上的属性吗?_C#_Interface_New Operator - Fatal编程技术网

你能用C#new关键字来扩展接口上的属性吗?

你能用C#new关键字来扩展接口上的属性吗?,c#,interface,new-operator,C#,Interface,New Operator,我理解“new”关键字如何在派生类中隐藏方法。但是,它对实现使用关键字的接口的类有什么影响 考虑这个例子,我决定通过读/写接口的属性来扩展接口 public interface IReadOnly { string Id { get; } } public interface ICanReadAndWrite : IReadOnly { new string Id { get; set; } } 然后你可以做这样的事情: pu

我理解“new”关键字如何在派生类中隐藏方法。但是,它对实现使用关键字的接口的类有什么影响

考虑这个例子,我决定通过读/写接口的属性来扩展接口

public interface IReadOnly {

   string Id {
      get;
   }
}

public interface ICanReadAndWrite : IReadOnly  {

   new string Id {
      get;
      set;
   }
}
然后你可以做这样的事情:

public IReadOnly SomeMethod() {
   // return an instance of ICanReadAndWrite
}
public interface IReadOnly
{
    string Id
    {
        get;
    }
}

public interface ICanReadAndWrite
{
    string Id
    {
        get;
        set;
    }
}
public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }

    public IReadOnly AsReadOnly()
    {
        return new ReadOnly(this);
    }
}

public class ReadOnly : IReadOnly
{
    private IReadOnly _WrappedObject;

    public ReadOnly(IReadOnly wrappedObject)
    {
        _WrappedObject = wrappedObject;
    }

    public string Id
    {
        get { return _WrappedObject.Id; }
    }
}
这个设计不好吗?它会不会给我实现ICAReadandWrite的类带来问题

编辑:下面是一个人为的例子,说明了我为什么要这样做:

public IReadOnly SomeMethod() {
   // return an instance of ICanReadAndWrite
}
public interface IReadOnly
{
    string Id
    {
        get;
    }
}

public interface ICanReadAndWrite
{
    string Id
    {
        get;
        set;
    }
}
public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }

    public IReadOnly AsReadOnly()
    {
        return new ReadOnly(this);
    }
}

public class ReadOnly : IReadOnly
{
    private IReadOnly _WrappedObject;

    public ReadOnly(IReadOnly wrappedObject)
    {
        _WrappedObject = wrappedObject;
    }

    public string Id
    {
        get { return _WrappedObject.Id; }
    }
}

假设我有一个返回IShoppingCartItemReadWrite的工厂类。然后,我可以有一个服务层来操纵它的价格、更改内容等。然后,我可以将这些对象作为IShoppingCartItemReadOnly传递给某种不会更改它们的表示层。(是的,我知道它在技术上可以改变它们——这是一个设计问题,不是安全性问题等等)

我不确定这是否编译,但这不是一个可取的模式。有了显式接口实现的能力,理论上可以为
Id
属性的
IReadOnly
icareadandwrite
版本提供两种完全不同的实现。考虑更改<代码> IcRead and Dead < /Cuff>接口,通过为属性添加Stter方法而不是替换属性。

< P>这不是一个特别糟糕的想法。您应该知道,实现者可以提供两种不同的实现(如果它隐式实现接口,那么单个读/写属性可以满足两个接口):

class Test : ICanReadAndWrite {
   public string Id {
      get { return "100"; }
      set { }
   }
   string IReadOnly.Id {
      get { return "10"; }
   }
}

Test t = new Test();
Console.WriteLine(t.Id);  // prints 100
Console.WriteLine(((IReadOnly)t).Id); // prints 10

顺便说一句,一般来说,
new
继承修饰符除了告诉编译器闭嘴,不要抛出“you's hidden that member”警告之外,什么都不做。省略它在编译的代码中没有任何效果。

这是完全合法的,并且对实现ICanReadAndWrite接口的类的影响是,当它被视为IReadOnly时,它只能读取,但是当我把它当作我的读写工具时,它可以同时做到这两个方面。

你可以做到,但我不确定你希望通过这样做实现什么

public IReadOnly SomeMethod() {
   // return an instance of ICanReadAndWrite
}
此方法将返回对
IReadOnly
的引用,这意味着您是否返回了
icareadandwrite
并不重要。这种方法不是更好吗

public interface IReadOnly
{
    String GetId();
}

public interface ICanReadAndWrite : IReadOnly
{
    String SetId();
}

您不应该基于IReadOnly实现ICanReadWrite,而应该将它们分开

例如:

public IReadOnly SomeMethod() {
   // return an instance of ICanReadAndWrite
}
public interface IReadOnly
{
    string Id
    {
        get;
    }
}

public interface ICanReadAndWrite
{
    string Id
    {
        get;
        set;
    }
}
public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }

    public IReadOnly AsReadOnly()
    {
        return new ReadOnly(this);
    }
}

public class ReadOnly : IReadOnly
{
    private IReadOnly _WrappedObject;

    public ReadOnly(IReadOnly wrappedObject)
    {
        _WrappedObject = wrappedObject;
    }

    public string Id
    {
        get { return _WrappedObject.Id; }
    }
}
下面是一个使用它们的类:

public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }
}
请注意,类中的同一属性可以支持这两个接口

请注意,根据注释,获得健壮解决方案的唯一方法是使用包装器对象

换句话说,这是不好的:

public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }

    public IReadOnly AsReadOnly()
    {
        return this;
    }
}
因为调用方可以执行以下操作:

ICanReadWrite rw = obj.AsReadOnly() as ICanReadWrite;
rw.Id = "123";
要获得健壮的解决方案,您需要一个包装器对象,如下所示:

public IReadOnly SomeMethod() {
   // return an instance of ICanReadAndWrite
}
public interface IReadOnly
{
    string Id
    {
        get;
    }
}

public interface ICanReadAndWrite
{
    string Id
    {
        get;
        set;
    }
}
public class SomeObject : IReadOnly, ICanReadWrite
{
    public string Id
    {
        get;
        set;
    }

    public IReadOnly AsReadOnly()
    {
        return new ReadOnly(this);
    }
}

public class ReadOnly : IReadOnly
{
    private IReadOnly _WrappedObject;

    public ReadOnly(IReadOnly wrappedObject)
    {
        _WrappedObject = wrappedObject;
    }

    public string Id
    {
        get { return _WrappedObject.Id; }
    }
}

在调用方使用反射之前,这将一直有效且健壮。

它肯定会编译。如果不添加新关键字,则会收到以下编译警告:“ICanReadAndWrite.Id”隐藏继承的成员“IReadOnly.Id”。如果打算隐藏,请使用new关键字。关于显式接口实现,我假设如果这样做,Id属性的两个完全不同的实现正是您想要的。我更感兴趣的是隐藏的gotchas,而不是这种方法可能导致的明显问题。遗憾的是,简单地在属性中添加setter是行不通的。如果setter对getter进行阴影处理,则读取该属性需要对具有未阴影的getter的类型进行类型转换。如果setter不影响getter,即独立的getter和setter都在作用域中,那么它们在C#或vb.net中都不可用。但是,您不能从ICAReader强制转换并写入IReadOnly。当您有一个处理读/写对象的类,然后只想将只读对象返回给使用者时,这是非常有用的。不过使用者可以回溯。这不是健壮的。当然,它不是健壮的,但是原始解决方案也不是健壮的,如果它有效的话。摆脱可写性的唯一方法是返回一个显式阻止它的包装对象,即仅实现IReadoly。首先,我原始问题中的代码可以编译并工作。而且它足够健壮——如果你对一个类型进行降级,你最好知道你在做什么+但是,对于关于只读包装器的注释,请参见1。是的,对不起,我在最初粘贴代码时输入了一些错误的代码,这使我相信代码有问题。然而,这是我的错,但我将留下评论。我想使用一个简单的属性。关于使编译器警告静音,这一点很好!但是,它会抱怨,因为对类定义执行类似操作会使它们以您可能不期望的方式运行。对于这个特殊的案例,我想不出任何意外的行为。。。这就是问题所在。是的。当然,这个警告是有原因的。正如我在回答中所说,唯一可能的问题是,您正在处理两个不同的方法槽,这两个方法槽可能会解析为不同的实现。这就是使用
new
的陷阱。对于
接口
来说,大多数情况下这并不有害,因为它们不提供任何实现,而且调用方希望该方法的任意实现。new关键字不是用于使编译器静音,而是用于明确说明“我不想覆盖任何成员,我的意图是隐藏它,并且我知道这一事实”. 警告是为了防止您“无意中隐藏成员”。是的,正如我在下面的评论中提到的,我希望显式实现两个接口的类有这样做的理由。@Pop Catalin:重点是,提及
new
不会影响代码生成。这是默认行为(事实并非如此)