我有两个类,两个类都有相同的方法(名称+类型+行为)和相同的属性(名称+类型)
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
和Country
类继承
在上面的代码中,您可以看到Person
类具有类似DisplayName
类的方法(Country
)。我正在寻找一种方法,以便两个类可以共享相同的方法代码,我想这样做,因为在我的真实代码 - 我想要分享的方法是非常大的,每当我在一个类中更改代码我必须复制粘贴它也在其他课堂上。我觉得这不是正确的方法。
请建议如何解决此问题。
答案 0 :(得分:2)
你说他们不能从公共基类继承,但你可以添加一个接口,对吗?我建议给每个人一个共同的界面。然后为该界面定义 extension method 。该方法将在VS中为每个人显示。
( Assumption :如果扩展方法访问的类成员是公共的或内部的,那么这将有效。)
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来执行您的通用逻辑。 (第一次遇到问题:确保扩展方法在同一个命名空间中,或者它的命名空间也包含在调用代码中。)
我不知道你是否对扩展方法不熟悉。它们非常强大。 (和许多强大的功能一样,它们可能被滥用)。 extension method on an interface一开始似乎很疯狂,直到你直接了解扩展方法是如何工作的。没有这个,LINQ就行不通了!
更新:我在上面看到你的评论,这些类不能从公共类继承,因为它们已经从一个公共类继承(我认为它不能过多地混淆)。我想指出选项2 ,基于此:创建一个国家/人/等的新类。将继承,它本身继承自现有的公共父类。现有的基类将成为祖父母类,可以这么说。如果 Country 和 Person 除了此DisplayName方法之外还有其他共同特征,那么这将成为更多的路径。如果您正在使用DisplayName,那么接口/扩展模式可能会更好。
答案 1 :(得分:1)
我建议在某些情况下避免使用扩展方法,当你需要对这两个类略有不同的实现时,你可能会遇到问题,然后你必须设计一个更通用的解决方案,EM会导致像多重继承一样的问题确实
作为更通用的OOD解决方案,我建议将此行为提取到由接口抽象的单独服务类中:
public interface IDisplayService()
{
void Display();
}
然后通过构造函数实现它并注入到这两个类中。
此外,您可以通过构造函数或甚至属性注入Action
或Func<>
,而不是引入接口和新类,然后通过调用注入的委托来调用此方法。
答案 2 :(得分:1)
定义界面
public interface INameable
{
string Name {get;}
}
然后添加扩展名
public static class INameableExt
{
public static void DisplayName(this INameable n)
{
// do your thing
}
}
答案 3 :(得分:0)
有两种选择:
Name
)实现一个接口,并为行为添加扩展方法(或者只是一个普通的静态方法)创建采用实例和lambda exppession访问注释成员的方法,例如
public static void Display<T>(T item, Func<T, string> nameGetter)
然后用(比如说)
来调用它DisplayHelper.Display(person, p => p.Name);
界面解决方案更清晰,但使用委托更灵活 - 您不需要能够更改所涉及的类,并且您可以应对小的变化(例如PersonName
vs {{ 1}} vs FooName
)
答案 4 :(得分:0)
您可以创建一个静态实用程序方法DisplayName()
,您可以传递显示所需的数据,或者使用组合并将所有属性和相应的方法(例如DisplayName()
)移动到单独的类中 - 然后使用来自Country
和Person
的此类的实例。
答案 5 :(得分:0)
您可以在单独的类中定义该big方法,然后在上述两个类中调用该方法。对于静态方法,您可以使用classname.methodname()
语法调用该方法。
对于非静态方法,您必须这样做:
classname obj=new classname();
obj.methodname();
答案 6 :(得分:0)
您可以实施策略模式:
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);
}
}
注意:注入具体策略可能更好。
答案 7 :(得分:0)
我想要的是C#中不允许的多类继承。 (但可以使用C ++,你没有这样做。)
所有其他人都已确定做了INTERFACE解决方案,可能是最好的方法。但是,根据您的描述,无论对象的类型是个人还是企业,您都拥有相同的单一代码块。并且您对大量代码的引用,您不希望在所有其他类中复制/粘贴相同的确切代码,这些类可能会使用类似的常见“事物”。
举个简单的例子,您有一个功能可以构建一个人的姓名和地址(或公司名称和地址)。您的代码需要一个名称和最多3个地址行,以及城市,州,邮政编码(或其他任何内容)。因此,这样的名称/地址信息的格式对于人与企业是相同的。您不希望在这两者之间反复复制这种确切的方法。但是,每个班级仍然有自己负责的事情。
我知道它是一个简单的上下文示例,但我认为可以解决这个问题。
仅定义接口的问题在于它不允许您实际实现您所指的CODE。
从您的示例中,我会考虑做一些事情的组合。创建一个静态类,其中包含您可能希望“全局”可用的方法。允许将一个参数传递给一个类的实例,该类具有一个接口类型,所有其他人都已表达,这将保证传入对象具有您期望的所有“部分”属性/方法,并使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;
}
}
答案 8 :(得分:0)
您可以使用组合:定义接口,实现它的类,然后让Person
和Country
通过调用实现类上的方法来实现接口:
// 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();
}
}
答案 9 :(得分:0)
警告:这里有很多未经测试的代码,因为我不同意基础假设“没有继承”,因此大肆猜测。
这样的事情可以帮助你。创建一个新的静态类并将代码粘贴到此处。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”作为参数调用它。
... public void DisplayName() { 显示名称(本); } ...
我想知道为什么你的类不允许从基类继承它,因为这是解决这个问题的最合适方法。