在 C# 中为抽象 class 的子类型实现重载方法
Implementing overload methods for subtypes of an abstract class in C#
我是 C# 的新手,我真的很想为定义的抽象的每个子类型实现特定的不同方法 class,但我无法弄清楚如何让编译器执行此操作适当地。例如:
public abstract class MasterClass { }
public class SubClass1 : MasterClass { }
public class SubClass2 : MasterClass { }
public class SeparateClass
{
public void HandleMasterClass(MasterClass item)
{
/*
stuff generic to both subclasses...
*/
SpecificMethod(item)
}
public void SpecificMethod(SubClass1 item)
{
//something specific to SubClass1
}
public void SpecificMethod(SubClass2 item)
{
//something specific to SubClass2
}
}
这个returns编译出错,因为没有SpecificMethod(MasterClass item)
,但我真正想要的是让它根据子class选择正确的方法,而不必编写单独的 HandleMasterClass(SubClass1 item)
和 HandleMasterClass(SubClass2 item)
方法,因为它们大部分是相同的代码
我的主要语言是 Jula,所以我非常习惯依赖多重调度并做这种事情。我知道它在 C# 中可能不是惯用的,那么我该如何做得更好?
编辑:表明这些方法不是免费的,而是单独 class
的一部分
这里有一个更好的具体例子
public abstract class MasterClass { public abstract int Stuff(); }
public class SubClass1 : MasterClass
{
public override int Stuff() { /*calculate and return an int*/ }
}
public class SubClass2 : MasterClass
{
public override int Stuff() { /*calculate and return an int*/ }
}
public class MasterClassDictionary
{
public Dictionary<int, SubClass1> subClass1Dict{get;} = new Dictionary<int, SubClass1>()
public Dictionary<int, SubClass2> subClass2Dict{get;} = new Dictionary<int, SubClass2>()
public void Add(MasterClass item)
{
int val = item.Stuff();
AddToDict(val, item);
}
void AddToDict(int val, SubClass1 item) { subClass1Dict[val] = item; }
void AddToDict(int val, SubClass2 item) { subClass2Dict[val] = item; }
}
我知道这是一个人为的例子,但它与我正在尝试做的相似。
通常,您想将特定于 class 的代码放入 class 中。因此,您的摘要 class 将使用 abstract
keyword, and the implementation would live inside the class, using the override
关键字定义特定的方法签名,如下所示:
public abstract class MasterClass {
public abstract void SpecificMethod();
}
public class SubClass1 : MasterClass {
public override void SpecificMethod()
{
//something specific to SubClass1
// use the this keyword to access the instance
}
}
public class SubClass2 : MasterClass {
public override void SpecificMethod()
{
//something specific to SubClass2
// use the this keyword to access the instance
}
}
public class SeparateClass
{
public void HandleMasterClass(MasterClass item)
{
/*
stuff generic to both subclasses...
*/
item.SpecificMethod()
}
}
根据您的评论,这就是我在您的具体示例中实现该功能的方式,尽管它可能不符合您的要求:
public class MasterClassDictionary
{
public Dictionary<int, SubClass1> subClass1Dict{get;} = new Dictionary<int, SubClass1>()
public Dictionary<int, SubClass2> subClass2Dict{get;} = new Dictionary<int, SubClass2>()
public void Add(MasterClass item)
{
int val = item.Stuff();
if (item is SubClass1)
{
subClass1Dict[val] = item;
}
if (item is SubClass2)
{
subClass2Dict[val] = item;
}
}
}
这种情况的标准设计模式是 Visitor pattern。这是一个有点复杂的模式,但基本思想是子类知道它们是什么类型,所以我们将通过一个名为 "Accept" 的虚方法调用它们,它们会将自己作为引用传回。他们回调的方法称为 Visit,并为所有可能的子类重载。这是您的示例的实现:
public abstract class MasterClass
{
public abstract int Stuff();
// New method that all subclasses will have to implement.
// You could also have this be virtual with an implementation
// for Visit(MasterClass) to provider a default behavior.
public abstract void Accept(IVisitor visitor);
}
public class SubClass1 : MasterClass
{
public override int Stuff() => 0;
// We must override this even though its the "same" code in both subclasses
// because 'this' is a reference to a different type.
public override void Accept(IVisitor visitor) => visitor.Visit(this);
}
public class SubClass2 : MasterClass
{
public override int Stuff() => 1;
// We must override this even though its the "same" code in both subclasses
// because 'this' is a reference to a different type.
public override void Accept(IVisitor visitor) => visitor.Visit(this);
}
public interface IVisitor
{
// Need an overload for all subclasses.
void Visit(SubClass1 item);
void Visit(SubClass2 item);
}
public class MasterClassDictionary
{
public Dictionary<SubClass1, int> subClass1Dict { get; } = new Dictionary<SubClass1, int>();
public Dictionary<SubClass2, int> subClass2Dict { get; } = new Dictionary<SubClass2, int>();
public void Add(MasterClass item)
{
int val = item.Stuff();
var visitor = new Visitor(this, val);
item.Accept(visitor);
}
void AddToDict(SubClass1 item, int val) { subClass1Dict[item] = val; }
void AddToDict(SubClass2 item, int val) { subClass2Dict[item] = val; }
// Provides the visitor implementation that holds any state that might
// be needed and dispatches to the appropriate method.
private class Visitor : IVisitor
{
private MasterClassDictionary _parent;
private int _value;
public Visitor(MasterClassDictionary parent, int val)
{
_parent = parent;
_value = val;
}
public void Visit(SubClass1 item) => _parent.AddToDict(item, _value);
public void Visit(SubClass2 item) => _parent.AddToDict(item, _value);
}
}
也就是说,C# 已经添加了带有 switch 的模式匹配,这看起来要简单得多。唯一的缺点是它进行了更多的类型检查,如果这是在一些真正对性能敏感的代码中,这可能会更慢,但肯定会比使用 dynamic
:
更快
public void Add(MasterClass item)
{
int val = item.Stuff();
switch (item)
{
case SubClass1 i: AddToDict(i, val); break;
case SubClass2 i: AddToDict(i, val); break;
}
}
我是 C# 的新手,我真的很想为定义的抽象的每个子类型实现特定的不同方法 class,但我无法弄清楚如何让编译器执行此操作适当地。例如:
public abstract class MasterClass { }
public class SubClass1 : MasterClass { }
public class SubClass2 : MasterClass { }
public class SeparateClass
{
public void HandleMasterClass(MasterClass item)
{
/*
stuff generic to both subclasses...
*/
SpecificMethod(item)
}
public void SpecificMethod(SubClass1 item)
{
//something specific to SubClass1
}
public void SpecificMethod(SubClass2 item)
{
//something specific to SubClass2
}
}
这个returns编译出错,因为没有SpecificMethod(MasterClass item)
,但我真正想要的是让它根据子class选择正确的方法,而不必编写单独的 HandleMasterClass(SubClass1 item)
和 HandleMasterClass(SubClass2 item)
方法,因为它们大部分是相同的代码
我的主要语言是 Jula,所以我非常习惯依赖多重调度并做这种事情。我知道它在 C# 中可能不是惯用的,那么我该如何做得更好?
编辑:表明这些方法不是免费的,而是单独 class
的一部分这里有一个更好的具体例子
public abstract class MasterClass { public abstract int Stuff(); }
public class SubClass1 : MasterClass
{
public override int Stuff() { /*calculate and return an int*/ }
}
public class SubClass2 : MasterClass
{
public override int Stuff() { /*calculate and return an int*/ }
}
public class MasterClassDictionary
{
public Dictionary<int, SubClass1> subClass1Dict{get;} = new Dictionary<int, SubClass1>()
public Dictionary<int, SubClass2> subClass2Dict{get;} = new Dictionary<int, SubClass2>()
public void Add(MasterClass item)
{
int val = item.Stuff();
AddToDict(val, item);
}
void AddToDict(int val, SubClass1 item) { subClass1Dict[val] = item; }
void AddToDict(int val, SubClass2 item) { subClass2Dict[val] = item; }
}
我知道这是一个人为的例子,但它与我正在尝试做的相似。
通常,您想将特定于 class 的代码放入 class 中。因此,您的摘要 class 将使用 abstract
keyword, and the implementation would live inside the class, using the override
关键字定义特定的方法签名,如下所示:
public abstract class MasterClass {
public abstract void SpecificMethod();
}
public class SubClass1 : MasterClass {
public override void SpecificMethod()
{
//something specific to SubClass1
// use the this keyword to access the instance
}
}
public class SubClass2 : MasterClass {
public override void SpecificMethod()
{
//something specific to SubClass2
// use the this keyword to access the instance
}
}
public class SeparateClass
{
public void HandleMasterClass(MasterClass item)
{
/*
stuff generic to both subclasses...
*/
item.SpecificMethod()
}
}
根据您的评论,这就是我在您的具体示例中实现该功能的方式,尽管它可能不符合您的要求:
public class MasterClassDictionary
{
public Dictionary<int, SubClass1> subClass1Dict{get;} = new Dictionary<int, SubClass1>()
public Dictionary<int, SubClass2> subClass2Dict{get;} = new Dictionary<int, SubClass2>()
public void Add(MasterClass item)
{
int val = item.Stuff();
if (item is SubClass1)
{
subClass1Dict[val] = item;
}
if (item is SubClass2)
{
subClass2Dict[val] = item;
}
}
}
这种情况的标准设计模式是 Visitor pattern。这是一个有点复杂的模式,但基本思想是子类知道它们是什么类型,所以我们将通过一个名为 "Accept" 的虚方法调用它们,它们会将自己作为引用传回。他们回调的方法称为 Visit,并为所有可能的子类重载。这是您的示例的实现:
public abstract class MasterClass
{
public abstract int Stuff();
// New method that all subclasses will have to implement.
// You could also have this be virtual with an implementation
// for Visit(MasterClass) to provider a default behavior.
public abstract void Accept(IVisitor visitor);
}
public class SubClass1 : MasterClass
{
public override int Stuff() => 0;
// We must override this even though its the "same" code in both subclasses
// because 'this' is a reference to a different type.
public override void Accept(IVisitor visitor) => visitor.Visit(this);
}
public class SubClass2 : MasterClass
{
public override int Stuff() => 1;
// We must override this even though its the "same" code in both subclasses
// because 'this' is a reference to a different type.
public override void Accept(IVisitor visitor) => visitor.Visit(this);
}
public interface IVisitor
{
// Need an overload for all subclasses.
void Visit(SubClass1 item);
void Visit(SubClass2 item);
}
public class MasterClassDictionary
{
public Dictionary<SubClass1, int> subClass1Dict { get; } = new Dictionary<SubClass1, int>();
public Dictionary<SubClass2, int> subClass2Dict { get; } = new Dictionary<SubClass2, int>();
public void Add(MasterClass item)
{
int val = item.Stuff();
var visitor = new Visitor(this, val);
item.Accept(visitor);
}
void AddToDict(SubClass1 item, int val) { subClass1Dict[item] = val; }
void AddToDict(SubClass2 item, int val) { subClass2Dict[item] = val; }
// Provides the visitor implementation that holds any state that might
// be needed and dispatches to the appropriate method.
private class Visitor : IVisitor
{
private MasterClassDictionary _parent;
private int _value;
public Visitor(MasterClassDictionary parent, int val)
{
_parent = parent;
_value = val;
}
public void Visit(SubClass1 item) => _parent.AddToDict(item, _value);
public void Visit(SubClass2 item) => _parent.AddToDict(item, _value);
}
}
也就是说,C# 已经添加了带有 switch 的模式匹配,这看起来要简单得多。唯一的缺点是它进行了更多的类型检查,如果这是在一些真正对性能敏感的代码中,这可能会更慢,但肯定会比使用 dynamic
:
public void Add(MasterClass item)
{
int val = item.Stuff();
switch (item)
{
case SubClass1 i: AddToDict(i, val); break;
case SubClass2 i: AddToDict(i, val); break;
}
}