C# 如何编写可由两个非继承类共享的方法
我有两个类,都有相同的方法(名称+类型+行为)和相同的属性(名称+类型) --C# 如何编写可由两个非继承类共享的方法,c#,.net,refactoring,polymorphism,C#,.net,Refactoring,Polymorphism,我有两个类,都有相同的方法(名称+类型+行为)和相同的属性(名称+类型) --Person和Country类不允许继承 在上面的代码中,您可以看到Person类具有类似的方法(DisplayName),如Country类。我正在寻找一种方法,使两个类可以共享相同的方法代码,我想这样做,因为在我真正的代码中,我想共享的方法非常大,每当我在一个类中更改代码时,我也必须复制粘贴到另一个类中。我觉得这不是正确的方法 请建议如何解决这个问题。您说它们不能从公共基类继承,但您可以添加一个接口,对吗?我建议给
Person
和Country
类不允许继承
在上面的代码中,您可以看到Person
类具有类似的方法(DisplayName
),如Country
类。我正在寻找一种方法,使两个类可以共享相同的方法代码,我想这样做,因为在我真正的代码中,我想共享的方法非常大,每当我在一个类中更改代码时,我也必须复制粘贴到另一个类中。我觉得这不是正确的方法
请建议如何解决这个问题。您说它们不能从公共基类继承,但您可以添加一个接口,对吗?我建议给他们每人一个通用的界面。然后为该接口定义一个。该方法将出现在VS中 (假设:如果扩展方法访问的类成员是公共的或内部的,那么这将起作用。) 。在与扩展方法相同的类中,定义(而不是作为扩展方法)一个函数doSomeDisplayLogic来执行公共逻辑。(首次发现:确保扩展方法位于同一名称空间中,或者其名称空间也包含在调用代码中。) 我不知道你对扩展方法是否陌生。他们非常强大。(和许多强大的功能一样,它们也可能被滥用)。一开始,扩展方法似乎很疯狂,直到你清楚地知道扩展方法是如何工作的。没有这个LINQ就不能工作 更新:我看到您在上面的评论,这些类不能从一个公共类继承,因为它们已经从一个公共类继承了(我认为这不会太麻烦)。我想指出一个选项2,基于此:创建一个新类,该类由Country/Person/etc.继承,该类本身从现有的公共父类继承。可以说,现有的基类将成为祖辈阶级。如果国家和个人除了这个显示名方法之外还有其他共同的特征,那么这将成为更多的途径。如果您只需要DisplayName,那么界面/扩展模式可能会更好。有几个选项:
- 使这两个类都为公共成员(
)实现一个接口,并为行为添加一个扩展方法(或者只是一个普通的静态方法)Name
- 创建使用实例和lambda表达式访问注释成员的方法,例如
public static void Display<T>(T item, Func<T, string> nameGetter)
接口解决方案更干净,但使用委托更灵活-您不需要更改所涉及的类,并且可以处理小的变化(例如
PersonName
vsFooName
vsName
)您可以创建静态实用程序方法DisplayName()
在一个单独的类中传递显示所需的数据,或使用组合并移动所有属性和相应的方法,如DisplayName()
,然后使用来自Country
和Person
的此类实例,我建议在某些情况下避免使用扩展方法,当两个类需要稍微不同的实现时,您可能会遇到问题,然后您必须设计一个更通用的解决方案,EM可能会导致与多重继承相同的问题
作为更通用的OOD解决方案,我建议将此行为提取到由接口抽象的单独服务类中:
public interface IDisplayService()
{
void Display();
}
然后实现它,并通过构造函数将注入到这两个类中
另外,您可以通过构造函数或甚至属性插入Action
或Func
,而不是引入接口和新类,然后通过调用插入的委托调用此方法。定义接口
public interface INameable
{
string Name {get;}
}
然后添加一个扩展名
public static class INameableExt
{
public static void DisplayName(this INameable n)
{
// do your thing
}
}
您可以在单独的类中定义该大方法,然后在上述两个类中调用该方法。对于静态方法,可以使用
classname.methodname()
语法调用该方法
对于非静态方法,必须执行以下操作:
classname obj=new classname();
obj.methodname();
您可以实施一种战略模式:
class DisplayNameStrategy<T> {
private readonly Func<T, string> nameSelector;
public void DisplayNameStrategy(Func<T, string> nameSelector) {
this.nameSelector = nameSelector;
}
public void abstract DisplayName(T t);
}
class WriteToConsoleDisplayNameStrategy<T> : DisplayNameStrategy<T> {
public void WriteToConsoleDisplayNameStrategy(Func<T, string> nameSelector)
: base(nameSelector) { }
public override void DisplayName(T t) {
Console.WriteLine(this.nameSelector(t));
}
public class Person {
private readonly DisplayNameStrategy<Person> displayNameStrategy =
new WriteToConsoleDisplayNameStrategy<Person>(x => x.Name);
public string Name { get; set; }
public void DisplayName() {
this.displayNameStrategy(this);
}
}
class显示名称策略{
专用只读Func名称选择器;
public void显示名称策略(Func namelector){
this.nameSelector=nameSelector;
}
公共无效摘要显示名(T);
}
类WriteToConsoleDisplayNameStrategy:DisplayNameStrategy{
公共无效写入控制台显示名称策略(Func nameSelector)
:base(nameSelector){}
公共覆盖无效显示名(T){
Console.WriteLine(this.nameSelector(t));
}
公共阶层人士{
私有只读显示名称策略显示名称策略=
新的WriteConsoleDisplayNames策略(x=>x.Name);
公共字符串名称{get;set;}
public void DisplayName(){
this.displayNameStrategy(this);
}
}
注:最好是注入具体策略。 < P>我想问的是C类中不允许的多类继承(但可以用C++,而不是你做的)。 所有其他人都已经确定了做一个接口解决方案,这可能是最好的方法。然而,从你的描述来看,无论对象类型是个人还是企业,你都有一个完全相同的代码块。而你对一个巨大代码块的引用,你不想在所有这些代码中复制/粘贴相同的代码e可能打算使用类似的常用“东西”来完成的其他类 举个简单的例子,您有一个功能可以构建一个人的姓名和地址(或企业名称和地址)。您的代码需要一个姓名和最多3个地址行,以及一个城市
public static class INameableExt
{
public static void DisplayName(this INameable n)
{
// do your thing
}
}
classname obj=new classname();
obj.methodname();
class DisplayNameStrategy<T> {
private readonly Func<T, string> nameSelector;
public void DisplayNameStrategy(Func<T, string> nameSelector) {
this.nameSelector = nameSelector;
}
public void abstract DisplayName(T t);
}
class WriteToConsoleDisplayNameStrategy<T> : DisplayNameStrategy<T> {
public void WriteToConsoleDisplayNameStrategy(Func<T, string> nameSelector)
: base(nameSelector) { }
public override void DisplayName(T t) {
Console.WriteLine(this.nameSelector(t));
}
public class Person {
private readonly DisplayNameStrategy<Person> displayNameStrategy =
new WriteToConsoleDisplayNameStrategy<Person>(x => x.Name);
public string Name { get; set; }
public void DisplayName() {
this.displayNameStrategy(this);
}
}
public interface ITheyHaveInCommon
{
string Name;
string GetOtherValue();
int SomethingElse;
}
public class Person : ITheyHaveInCommon
{
// rest of your delcarations for the required contract elements
// of the ITheyHaveInCommon interface...
}
public class Country : ITheyHaveInCommon
{
// rest of your delcarations for the required contract elements
// of the ITheyHaveInCommon interface...
}
public static class MyGlobalFunctions
{
public static string CommonFunction1( ITheyHaveInCommon incomingParm )
{
// now, you can act on ANY type of control that uses the
// ITheyHaveInCommon interface...
string Test = incomingParm.Name
+ incomingParm.GetOtherValue()
+ incomingParm.SomethingElse.ToString();
// blah blah with whatever else is in your "huge" function
return Test;
}
}
// the interface
public interface IName {
string Name { get; set; }
void DisplayName();
}
// a class that implements the interface with actual code
public class NameImpl : IName {
public string Name { get; set; }
public void DisplayName() {
Console.WriteLine(this.Name);
}
}
public class Country : IName {
// instance of the class that actually implements the interface
IName iname = new NameImpl();
// forward calls to implementation
public string Name {
get { return iname.Name; }
set { iname.Name = value; }
}
public void DisplayName() {
// forward calls to implementation
iname.DisplayName();
}
}
public static class Display
{
public static void DisplayName<T>(T obj)
{
if ((T is Person) || (T is Country) || (T is whateveryouwant))
{
//do stuff
}
}
}