C# 关于抽象的建议

C# 关于抽象的建议,c#,abstraction,C#,Abstraction,我正在编写一些代码,其中有一个抽象类,它有一些核心属性和一个Run(int-index)方法。然后,我创建新类型来继承它。这些新类型可以有多个方法,可以根据传入的索引调用这些方法 public abstract class BaseClass { public abstract void Run(int index); } public class Class1 : BaseClass { public override void Run(int index) {

我正在编写一些代码,其中有一个抽象类,它有一些核心属性和一个Run(int-index)方法。然后,我创建新类型来继承它。这些新类型可以有多个方法,可以根据传入的索引调用这些方法

public abstract class BaseClass
{
    public abstract void Run(int index);
}


public class Class1 : BaseClass
{

    public override void Run(int index)
    {
        if (index == 0)
        {
            MethodA(); 
        }
        else if (index == 1)
        {
            MethodB();
        }
    }

    private void MethodA()
    {
        //do stuff
    }

    private void MethodB()
    {
        //do stuff
    }
}
我只是想知道有没有更好的办法。这些类型和方法将从UI调用,例如,单击菜单。所以我可能有一个1班和一个2班。Class1可能有3个方法,因此我可以调用run(0)。。。在上面运行(2)。类2可能只有一个内部方法,所以我只调用run(0)。也许我需要为每个类保留一个int集合,作为方法的映射。可能还必须向该集合添加字符串,以保存菜单项等的友好名称

您能想出一种方法来实现这种类型的映射,同时保持尽可能多的抽象吗?有没有比我现在的想法更好的方法呢?

一种方法:

您可以改用接口:

public interface IRunnableSomething {
    void Run();
}

public class MyRunnableA :IRunnableSomething  
{
    public void Run() {
        // do stuff
    }
}

public class MyRunnableB :IRunnableSomething 
{
    public void Run() {
        // do stuff
    }
}
然后在你的主课上

public override void Run(IRunnable runnable)
{
    runnable.Run();
}
调用它的示例:

myInstanceOfMainClass.Run(new MyRunnableA());

这似乎很合适,因为您已经知道原始版本传递的
索引是什么。这只是将它从基于
int
移动到基于
interface
(最后代码也更少)。

让我进一步解释一下。这里有一个稍微详细一点的版本,我正在尝试做什么。您可以在这里看到,我的抽象类有一个索引列表,用于指向派生类中的正确方法,您可以看到我在UI中加载类型和创建菜单项的位置。我正在使用这个ItemPointer列表,并将ItemPointer传递给标记属性等。不知何故,这一切都感觉有点错误

我希望整个事情都可以扩展。我可能想添加一个Class2、Class3等所有继承基类的类。我可能还想使用基类创建插件。任何派生类都将至少有一个但可运行的方法,但可能有许多。这里的Class1只是一个例子。这有助于解释我自己吗?请对我放松点,我正在学习,这就是为什么我在这里问

我在这里做的很糟糕吗?还是可以?还是有更好的办法?我想这是我的问题。如果有更好的方法,我真的很想举个例子。非常感谢大家的帮助。非常感谢

public abstract class BaseClass
{
    public List<ItemPointer> ItemPointers = new List<ItemPointer>();
    public abstract void Run(int index);
}



public class ItemPointer
{
    public int Index { get; set; }
    public string ClassType { get; set; }
    public string UIDescription { get; set; }
}



public class Class1 : BaseClass
{
    public Class1()
    {
        ItemPointers.Add(new ItemPointer { Index = 0, ClassType = this.GetType().Name,  UIDescription = "MethodA Description" });
        ItemPointers.Add(new ItemPointer { Index = 1, ClassType = this.GetType().Name,  UIDescription = "MethodB Description" });
    }

    public override void Run(int index)
    {            
        if (index == 0)
        {
            MethodA();
        }
        else if (index == 1)
        {
            MethodB();
        }
    }

    private void MethodA()
    {
        //do stuff
    }

    private void MethodB()
    {
        //do stuff
    }
}



public class UIForm
{
    private List<BaseClass> _baseClasses;

    //Formload events load all baseclass types (including plugins via reflection during form init etc. Then call loadUIitems

    private void LoadUIItems()
    {
        foreach (BaseClass bc in _baseClasses)
        {
            foreach (var p in bc.ItemPointers)
            {
                ToolStripMenuItem t = new ToolStripMenuItem(p.UIDescription);
                t.Click += new EventHandler(WorkerMenu_Click);
                t.Tag = p;
                actionsToolStripMenuItem.DropDownItems.Add(t);  
            }
        }
    }



    void WorkerMenu_Click(object sender, EventArgs e)
    {
        ToolStripMenuItem t = (ToolStripMenuItem)sender;
        ItemPointer p = (ItemPointer)t.Tag;

        foreach (BaseClass bc in _baseClasses)
        {
            if (bc.GetType().Name == p.ClassType)
            {
                bc.Run(p.Index);
            }
        }
    }
}
公共抽象类基类
{
public List ItemPointers=new List();
公开摘要无效运行(int索引);
}
公共类项指针
{
公共int索引{get;set;}
公共字符串类类型{get;set;}
公共字符串UIDescription{get;set;}
}
公共类1:基类
{
公共类别1()
{
添加(新的ItemPointers{Index=0,ClassType=this.GetType().Name,UIDescription=“MethodA Description”});
添加(新的ItemPointers{Index=1,ClassType=this.GetType().Name,UIDescription=“MethodB Description”});
}
公共覆盖无效运行(整数索引)
{            
如果(索引==0)
{
方法a();
}
else if(索引==1)
{
方法b();
}
}
私有无效方法a()
{
//做事
}
私有无效方法b()
{
//做事
}
}
公共类UIForm
{
私有列表基类;
//Formload事件加载所有基类类型(包括在form init期间通过反射加载的插件等),然后调用loadUIitems
私有void LoadUIItems()
{
foreach(基类bc在_基类中)
{
foreach(bc.ItemPointers中的var p)
{
ToolStripMenuItem t=新ToolStripMenuItem(p.UIDescription);
t、 单击+=新建事件处理程序(工作菜单单击);
t、 Tag=p;
actionsToolStripMenuItem.DropDownItems.Add(t);
}
}
}
无效工作菜单单击(对象发送者,事件参数e)
{
ToolStripMenuItem t=(ToolStripMenuItem)发送方;
ItemPointer p=(ItemPointer)t.Tag;
foreach(基类bc在_基类中)
{
if(bc.GetType().Name==p.ClassType)
{
bc.Run(p.Index);
}
}
}
}

在你的位置上,我可能倾向于尝试这样做:

void Main()
{
    var a = new Class1();
    var b = new Class2();

    try
    {           
        a.Run("Foo");
        b.Run("Bar", "Yoda");
        b.Run("Bat"); // throws exception
    }
    catch (Exception ex)
    {
        Console.WriteLine (ex.Message);
    }
}

class Base
{
    public void Run(string commandName, params object[] args)
    {
        var method = this.GetType().GetMethod(commandName);
        if(method != null)
            method.Invoke(this, args);
        else
            throw new Exception("the command " + commandName + " does not exist on " + this.GetType().Name);
    }
}

class Class1 : Base
{
    public void Foo()
    {
        Console.WriteLine ("I am foo");
    }
}

class Class2 : Base
{
    public void Bar(string str)
    {
        Console.WriteLine ("I am {0}", str);
    }
}
输出:

I am foo
I am Yoda
the command Bat does not exist on Class2

我想你忘了在每个类中都包含
:IRunnableSomething
。我确实这样做了。直接在浏览器中键入的危险!:)非常感谢你的回复,但你已经失去了我。界面的意义是什么?假设MyRunnableB类有4个我可能想要运行的方法,我现在必须为每个方法创建类型?例如,如果我想用插件扩展项目,会发生什么?@user2026382这通常是一个很好的信息,可以包含在您的问题中。这个回答似乎完全符合你最初的问题。。但如果您打算扩展它,则不会。问题似乎是“我发明了Windows消息循环…现在是什么?”-我建议跳过这些最初的痛苦版本,直接使用一些最近的强类型事件事件机制。。。