你认为“自动接口实现”在.NET / C#中有用吗?

bvk5enib  于 2023-11-20  发布在  .NET
关注(0)|答案(9)|浏览(105)

就目前而言,这个问题不适合我们的问答形式。我们希望答案能得到事实、参考资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或广泛的讨论。如果您认为这个问题可以改进,并可能重新开放,请visit the help center寻求指导。
十二年前就关门了。
想想这个:

public class interface Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

字符串
还有这个:

public class StubPerson : IPerson
{
    int ID { get { return 0; protected set { } }
    string FirstName { get { return "Test" } set { } }
    string LastName { get { return "User" } set { } }
    string FullName { get { return FirstName + " " + LastName; } }
}


使用方法:

IPerson iperson = new Person();


或者:

IPerson ipersonStub = new StubPerson();


或者:

IPerson ipersonMock = mocks.CreateMock<IPerson>();


所以实际上我们是在同时声明IPerson接口和Person类:

public class interface Person : IPerson

你认为在.NET/C#中提供这种支持会有用吗?
编辑:

由于大量的混乱,我认为我需要澄清拟议的目的:
如果没有这个功能,你必须写:

interface IPerson
{
  int ID { get; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get; }
}


还有这个

public class Person : IPerson
{
  int ID { get; protected set; }
  string FirstName { get; set; }
  string LastName { get; set; }
  string FullName { get { return FirstName + " " + LastName; } }
}

我根本没有提出任何语义上的变化。

ijnw1ujt

ijnw1ujt1#

让我看看我是否理解你的问题:
为什么我们不能声明一个接口:

interface IPerson
{
    string Name {get;set;}
    int ID {get;set;}
}

字符串
实现该接口的类将继承其属性,而无需重新声明它们:

class Person : IPerson { } 
//person now has properties Name and ID


你不能这样做的原因是,即使你的接口代码和你的类代码的文本非常相似,它们 * 意味着非常 * 不同的事情。接口只是说“implementor将有一个带有getter和setter的字符串Name”。它是说“当调用getter for name时返回私有字段”的类。即使你使用auto-property快捷方式让编译器实现那个逻辑,它仍然是 * 逻辑 *,属于类。只是因为:

string Name {get;set;}


在一个接口和一个类中看起来是一样的,这并不意味着甚至是远程相同的事情。
如果编译器在编译时没有抱怨你没有实现它们,而是实现任意的逻辑来为你实现你的合约,这将是非常危险的。这可能会引入非常难以追踪的bug。当没有定义任何行为时,让编译器回退到默认行为是一个非常非常糟糕的主意。

nfs0ujit

nfs0ujit2#

我考虑过the same sort of thing a while ago,特别是当你只有一个接口的生产实现,但你想模拟它进行测试的时候。目前它有点像以前的.c/.h文件。
最后,我怀疑它的好处被语言和之后阅读代码的额外复杂性所抵消。尽管如此,我仍然有兴趣看到它被更彻底地探索。即使这样,我的优先级列表上还有其他更高的事情-更好地支持不变性是最重要的:)

oo7oh9g9

oo7oh9g93#

我相信Eiffel在.NET上做了类似的事情,为了支持多重继承。类声明自动产生相应的接口。当引用类类型时,编译器大多会发出对接口类型的引用。当然,主要的例外是构造函数表达式。

jexiocij

jexiocij4#

我认为其他的答案将帮助你理解在不同的具体类中使用接口来抽象逻辑,我还认为你可以使用VS中内置的重构工具来完成类似于你想要的东西。
定义您的类...

public class Person
{
  public int ID { get; protected set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string FullName { get { return FirstName + " " + LastName; } }
}

字符串
然后右键单击,选择Refactor -> Extract Interface。
这将创建一个单独的文件,其中包含用于定义类的接口,然后可以相应地塑造接口和实现类。
提取接口:

interface IPerson
{
    string FirstName { get; set; }
    string FullName { get; }
    int ID { get; }
    string LastName { get; set; }
}

czq61nw1

czq61nw15#

我想我没有抓住重点--你把类和接口混合在一起能实现什么?你用这种方法解决了什么问题?
这一点:

IPerson iperson = new Person();

字符串
在C#中已经是法律的了。

**编辑:**澄清-上面的代码是法律的给出以下:

interface IPerson { }

class Person : IPerson { }

omvjsjqw

omvjsjqw6#

如果我请求Visual Studio这样做,我至少希望它能从接口中实现我的属性作为自动属性。
不幸的是,这个选项没有,我必须处理未实现的异常存根

f87krz0w

f87krz0w7#

不可以,因为这样会强制你暴露接口的所有公共成员。试试ReSharper,再也不用担心这个问题了。

7uzetpgm

7uzetpgm8#

Resharper可以提供此功能,例如,
1.你可以先写Person类。
1.您可以通过将成员拉到IPerson接口来提取接口。
因此,您可以让Visual Studio自动为您生成实现存根。

更新

不管怎样,让我们先来解释一下接口,引用你在问题中提供的代码:

public class interface Person : IPerson
{
    int ID { get; protected set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get { return FirstName + " " + LastName; } }
}

字符串
你必须明白接口不是抽象类,接口仅仅是一个契约,一个蓝图,这意味着它会告诉一个对象在另一个对象中期望什么,而不关心它是如何实现的。
另一方面,抽象类可以包含可以继承和重写的功能片段。
在上面的例子中,你的“接口”是无效的,因为:

  • 你不能在接口上声明作用域约束(public,private,protected,internal),因为这是一个实现细节
  • 你不能声明一个默认的实现(例如,你的FullName属性),因为这是一个实现细节

在我看来,你真正想要的是一个抽象类,例如,

public abstract class BasePerson
{
    public abstract int ID { get; protected set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual string FullName { get { return FirstName + " " + LastName; } } 
}


我只是猜测,但也许那才是你真正需要的。

更新2

好吧,我想我已经明白你想要发生什么了,所以你想要的是能够这样写:

public interface IPerson
{
    int ID { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    string FullName { get; }
}


然后对于你的实现只需要这样写:

public class Person : IPerson
{
    public int ID { get; protected set; }
    public string FullName { get { return FirstName + " " + LastName; } } 
}


而不需要指定FirstName和LastName属性。
我们需要解决的第一个问题是接口在其实现中不允许访问分隔符:会发生的情况是属性将继承默认的访问分隔符,这是私有的。
第二个事实是,虽然在我们眼中接口中的string FirstName { get; set; }和类中的public string FirstName { get; set; }是相同的,但它们实际上不是:

  • 在接口中,属性定义将指示getter和/或setter方法的方法签名将可用于实现该接口的所有类。
  • 在一个类中,属性定义将指示对象创建一个匿名对象,该对象将保存所述属性的值。

对程序员来说是细微的差别,对编译器来说却是天壤之别。
最后,当您指定要实现一个接口时,Visual Studio会执行语法魔法,自动为您生成这些属性存根。

kgqe7b3p

kgqe7b3p9#

我认为一个更好的抽象是trait,或者像我描述的here,一个角色。这就像一个带有代码的接口。你的例子可以这样编码:

public role RPerson { 
  int ID { get; protected set; } 
  string FirstName { get; set; } 
  string LastName { get; set; } 
  string FullName { get { return FirstName + " " + LastName; } } 
} 

public class Person : RPerson { }

public class StubPerson : RPerson { 
    int ID { get { return 0; protected set { } } 
    string FirstName { get { return "Test" } set { } } 
    string LastName { get { return "User" } set { } } 
    string FullName { get { return FirstName + " " + LastName; } } 
} 

// ...

RPerson rperson = new Person(); 

RPerson rpersonStub = new StubPerson();

字符串

相关问题