如何编写一个可以被两个非继承类共享的方法

发布于 2024-12-10 09:07:01 字数 648 浏览 1 评论 0原文

我有 2 个类,都具有相同的方法(名称 + 类型 + 行为)和相同的属性(名称 + 类型)

public class Country
{
    public string Name { get; set; }

    public void DisplayName()
    {
        Console.WriteLine(this.Name);
    }
}

public class Person
{
    public string Name { get; set; }

    public void DisplayName()
    {
        Console.WriteLine(this.Name);
    }
}

- 不允许 PersonCountry 类继承

在上面的代码中,您可以看到 Person 类具有与 Country 类类似的方法(DisplayName)。我正在寻找一种方法,以便两个类可以共享相同的方法代码,我想这样做,因为在我的真实代码中-我想共享的方法非常大,每当我更改一个类中的代码时,我都必须复制粘贴在其他班级也是如此。我觉得这不是正确的方法。

请建议如何解决这个问题。

I am having 2 classes, both having a same method(name + type +behavior) and a same property (name + type)

public class Country
{
    public string Name { get; set; }

    public void DisplayName()
    {
        Console.WriteLine(this.Name);
    }
}

public class Person
{
    public string Name { get; set; }

    public void DisplayName()
    {
        Console.WriteLine(this.Name);
    }
}

-- Person and Country classes are not allowed to inherit

In the above code you can see Person class has similar method(DisplayName) like Country class. I am looking for a way so that both classes can share the same method codes, i want to do this because in my real codes- Method which i want to share is very big and whenever i change code in one class i have to copy paste it in other class too. That i feel is not the correct way.

Please suggest how to resolve this problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

吾家有女初长成 2024-12-17 09:07:01

你说它们不能从公共基类继承,但你可以添加一个接口,对吗?我建议为他们每个人提供一个通用的界面。然后为该接口定义一个扩展方法 。 VS 中将出现每个方法的方法。

假设:如果扩展方法访问的类成员是公共的或内部的,这将起作用。)

interface IDisplayable
{
    string Name {get; set;}
}

public class Country : IDisplayable
{
    public string Name { get; set; }
}

public class Person : IDisplayable
{
    public string Name { get; set; }
}

public static void DisplayName(this iDisplayable d)
{
    return doSomeDisplayLogic(d.Name);
}

。 。 。在与扩展方法相同的类中,定义(不是作为扩展方法)函数 doSomeDisplayLogic 来执行通用逻辑。 (第一次遇到的问题:确保扩展方法位于同一个命名空间中,或者其命名空间也包含在调用代码中。)

我不知道您是否是扩展方法的新手。他们非常强大。 (就像许多强大的功能一样,它们也可能被滥用)。 接口上的扩展方法乍一看似乎很疯狂,直到您清楚地了解扩展方法的真正工作原理。如果没有这个,LINQ 将无法工作!

更新:我在上面看到您的评论,这些类不能从公共类继承,因为它们已经从公共类继承(我认为不能弄乱太多)。我想指出一个选项2,基于此:创建一个国家/人/等的新类。将继承自,它本身继承自现有的公共父类。可以这么说,现有的基类将成为祖父母类。如果 CountryPerson 除了此 DisplayName 方法之外还有其他共同特征,那么这将成为更可行的路线。如果您只需要 DisplayName,那么接口/扩展模式可能会更好。

You say they cannot inherit from a common base class, but you could add an interface, right? I suggest giving them each a common interface. Then define an extension method for that interface. The method will appear for each of them in VS.

(Assumption: this will work if the class members accessed by the extension methods are public or internal.)

interface IDisplayable
{
    string Name {get; set;}
}

public class Country : IDisplayable
{
    public string Name { get; set; }
}

public class Person : IDisplayable
{
    public string Name { get; set; }
}

public static void DisplayName(this iDisplayable d)
{
    return doSomeDisplayLogic(d.Name);
}

. . . And in the same class as your extension method, define (not as an extension method) a function doSomeDisplayLogic to do your common logic. (first-time gotcha: make sure the extension method is in the same Namespace or the its namespace is also included in the calling code.)

I don't know if you're new to extension methods or not. They are very powerful. (And like many powerful features, they can be abused). An extension method on an interface seems crazy at first, until you get straight in your head how extension methods really work. LINQ wouldn't work without this!

Update: I see your comment above that the classes can't inherit from a common class, because they are already inheriting from a common class (which I assume can't be messed with too much). I would like to point out an Option 2, based on this: Creating a new class that Country/Person/etc. will inherit from, that itself inherits from the existing common parent class. The existing base class would become a grandparent class, so to speak. This would become more the route to go if Country and Person have other common characteristics besides this DisplayName method. If DisplayName is all you're after, the Interface/Extension pattern might be better.

蓝礼 2024-12-17 09:07:01

定义一个接口

public interface INameable
{
    string Name {get;}
}

然后添加一个扩展

public static class INameableExt
{
    public static void DisplayName(this INameable n)
    {
        // do your thing
    }
}

Define an interface

public interface INameable
{
    string Name {get;}
}

then add an extension

public static class INameableExt
{
    public static void DisplayName(this INameable n)
    {
        // do your thing
    }
}
那伤。 2024-12-17 09:07:01

我建议在某些情况下避免扩展方法,当您需要两个类的实现略有不同时,您可能会遇到问题,然后您必须设计一个更通用的解决方案,EM 可能会导致与多重继承相同的问题。

作为更通用的 OOD 解决方案,我建议将此行为提取到由接口抽象的单独服务类中:

public interface IDisplayService()
{
    void Display();
}

然后实现它并通过构造函数注入到两个类中。

此外,您可以通过构造函数甚至属性注入 ActionFunc<>,而不是引入接口和新类,然后通过调用注入的委托来调用此方法。

I would suggest to avoid Extension Methods in some cases, you can ran into a problem when you need slightly a different implementation for both classes and then you have to design a more generic solution, EM can cause the same issues like multiple inheritance does.

As more generic OOD solution I would suggest to extract this behaviour into a separate service class abstracted by an interface:

public interface IDisplayService()
{
    void Display();
}

Then implement it and inject into both classes via constructor.

Also, instead of introducing the interfaces and new classes you can inject Action or Func<> via constructor or even property and then call this method by invoking an injected in delegate.

诗酒趁年少 2024-12-17 09:07:01

您可以创建一个静态实用方法 DisplayName() 来传递显示所需的数据,或者使用组合并移动所有属性和相应的方法,例如 DisplayName()一个单独的类 - 然后使用来自 CountryPerson 的此类实例。

You could create either a static utility method DisplayName() that you pass the data needed for display, or use composition and move all properties and corresponding methods such as DisplayName() in a separate class - then use an instance of this class from both Country and Person.

等风来 2024-12-17 09:07:01

您可以实现策略模式:

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

注意:注入具体策略可能会更好。

You could implement a strategy pattern:

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

Note: it's probably better to inject the concrete strategy.

慵挽 2024-12-17 09:07:01

您可以使用组合:定义一个接口、一个实现该接口的类,然后让 PersonCountry 通过调用实现类上的方法来实现该接口:

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

You could use composition: define an interface, a class that implements it, and then have Person and Country implement the interface by calling methods on the implementation class:

// 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();
    }
}
硬不硬你别怂 2024-12-17 09:07:01

我认为您要求的是多类继承,这在 C# 中是不允许的。 (但可以使用 C++,但你没有这样做)。

所有其他人都已确定采用接口解决方案,这可能是最好的方法。但是,根据您的描述,无论对象类型是个人还是企业,您都有一个相同的代码块。当您引用大量代码时,您不想在可能打算使用类似的常见“事物”来完成的所有其他类中复制/粘贴相同的确切代码。

举个简单的例子,您有一个功能可以构建一个人的姓名和地址(或公司名称和地址)。您的代码需要名称和最多 3 个地址行,以及城市、州、邮政编码(或其他任何内容)。因此,此类名称/地址信息的格式对于个人和企业来说是相同的。您不想在两者之间一遍又一遍地复制这个确切的方法。然而,每个单独的类仍然有自己负责的事情。

我知道这是一个简单的上下文示例,但我认为它已经表达了要点。

仅定义接口的问题是它不允许您实际实现您所引用的代码。

从您的示例中,我会考虑做一些事情的组合。创建一个静态类,其中包含您可能希望“全局”可用的方法。允许将一个参数传递给一个类的实例,该类的实例具有所有其他人都表达的接口类型,这将保证传入的对象具有您期望的所有“部分”属性/方法,并让 IT 进行操作根据需要。像这样的东西

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

What I THINK you are asking for is multiple class inheritance which is not allowed in C#. (but can be with C++ which you are NOT doing).

All the others have identified doing an INTERFACE solution, and probably the best way to go. However, from your description, you have a SINGLE BLOCK of code that is identical regardless of the type of object being a person or a business. And your reference to a huge block of code, you don't want to copy/paste that same exact code among all the other classes that may be intended to use similar common "thing" to be done.

For simple example, you have a functionality that builds out a person's name and address (or business name and address). You have code that is expecting a name and up to 3 address lines, plus a city, state, zip code (or whatever else). So, the formatting of such name/address information is the same for a person vs a business. You don't want to copy this exact method over and over between the two. However, each individual class still has its own things that it is responsible for.

I know its a simple example for context, but I think gets the point across.

The problem with just defining an Interface is that it won't allow you to actually implement the CODE you are referring to.

From your sample, I would consider doing a combination of things.. Create a static class with methods on it that you might want as "globally" available. Allow a parameter to be passed into it of an instance of a class that has a type of interface all the others have expressed that will guarantee the incoming object has all the "pieces" of properties / methods you are expecting, and have IT operate on it as needed. Something like

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;
   }
}
溺孤伤于心 2024-12-17 09:07:01

警告:这里有很多未经测试的代码,主要是疯狂猜测,因为我不同意“无继承”的基本假设。

像这样的东西应该对你有帮助。创建一个新的静态类并将您的代码粘贴到此处。

public static class Display
{
    public static void DisplayName<T>(T obj)
    {
        if ((T is Person) || (T is Country) || (T is whateveryouwant))
        {
            //do stuff
        }
    }
}

在您的类中,重构 ShowDisplayName() 以使用“this”作为参数来调用它。

...
公共无效显示名称()
{
显示名称(此);
}
...

我想知道为什么你的类不允许从基类继承它,因为恕我直言,这是解决这个问题的最正确方法。

warning: lots of untested code here, wild guessing mostly since i disagree with the base assumption "no inheritance".

something like this should help you. create a new static class and paste your code in here.

public static class Display
{
    public static void DisplayName<T>(T obj)
    {
        if ((T is Person) || (T is Country) || (T is whateveryouwant))
        {
            //do stuff
        }
    }
}

in your classes, refactor ShowDisplayName() to call that with "this" as parameter.

...
public void DisplayName()
{
DisplayName(this);
}
...

I wonder why your classes are not allowed to inherit it from a base class, since that's imho the right-est way to solve this.

半步萧音过轻尘 2024-12-17 09:07:01

有几个选项:

  • 使两个类都实现公共成员的接口(Name),并为行为添加扩展方法(或只是普通的静态方法)
  • 创建采用实例的方法和一个 lambda 表达式来访问评论成员,例如

    public static void Display(T item, Func nameGetter)
    

    然后你可以用(比如说)来调用它

    DisplayHelper.Display(person, p => p.Name);
    

接口解决方案是更干净的解决方案,但使用委托更灵活- 您不需要能够更改所涉及的类,并且可以应对小的变化(例如 PersonNameFooNameName

A couple of options:

  • Make both classes implement an interface for the common members (Name) and add an extension method for the behaviour (or just a normal static method)
  • Create methods which take an instance and a lambda exppession to access the comment members, e.g.

    public static void Display<T>(T item, Func<T, string> nameGetter)
    

    You'd then call it with (say)

    DisplayHelper.Display(person, p => p.Name);
    

The interface solution is the cleaner one, but using a delegate is more flexible - you don't need to be able to change the classes involved, and you can cope with small variations (e.g. PersonName vs FooName vs Name)

花开柳相依 2024-12-17 09:07:01

您可以在单独的类中定义该大方法,然后在上述两个类中调用该方法。对于静态方法,您可以使用 classname.methodname() 语法调用该方法。

对于非静态方法,您必须这样做:

classname obj=new classname();
obj.methodname();

You can define that big method in a separate class and then call the method in both the above classes. For a static method, you can call the method using classname.methodname() syntax.

For a non static method, you will have to do this:

classname obj=new classname();
obj.methodname();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文