Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.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# 如何编写可由两个非继承类共享的方法_C#_.net_Refactoring_Polymorphism - Fatal编程技术网

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
vs
FooName
vs
Name

您可以创建静态实用程序方法
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
        }
    }
}