【问题标题】:I need some C# generics clarification我需要一些 C# 泛型说明
【发布时间】:2023-04-01 11:19:01
【问题描述】:

我这里有点问题。我使用的是泛型类,但在从 UI 面板选择之前我不知道类型。如何在知道对象的类型之前声明我的对象? 所以这里是示例

public class UI
{
    Agent myAgent;
    public UI()
    {
    }
    public void Initialize()
    {
        if (textBox1.Text == "LabAgent")
            myAgent = new Agent<LabState, LabAction>();
        else
            myAgent = new Agent<FieldState, FieldAction>();
    }
}

Agent 类是一个简单的泛型类。我怎样才能做出这样的事情,但要真正发挥作用?如何在不知道类型的情况下定义 myAgent? 注意:我使用 C#,而不是 Java。 编辑1:

public class Agent<S,A>
    where S : AState
    where A : AAction
{
    private List<S> states;
    private List<A> actions;

    private Dictionary<KeyValuePair<S, A>, float> Q;

    private S stareCurenta;

    public void Initializare()
    {
        foreach (S s in states)
        {
            foreach (A a in actions)
            {
                Q.Add(new KeyValuePair<S, A>(s, a), 32000);
            }
        }
    }
}

【问题讨论】:

  • 您可以通过接口和协变来实现这一点,但只有在 Agent 类中以只读方式使用类型时才应该使用它。
  • KeyValuePair 不适合用作字典中的键。您可能想改用Tuple&lt;S, A&gt;
  • 哦,谢谢!到目前为止没有使用元组。能否请您解释一下两者之间的区别?
  • Tuple 仅表示 n 个单独对象的组合,而 KeyValuePair 表示专门表示键和值的组合。
  • 根据您的更新,我看不出statesactions 将如何被填充,因此Initializare 并没有真正做任何事情。

标签: c# class object generics abstract


【解决方案1】:

不知道类型如何定义myAgent?

你不能。 Agent&lt;LabState, LabAction&gt;Agent&lt;FieldAgent, FieldAction&gt; 是完全不同的类型。如果您尝试在另一种方法中使用myAgent,您如何在编译时知道它是Agent&lt;LabState, LabAction&gt; 还是Agent&lt;FieldAgent, FieldAction&gt;,因此编译器如何绑定到任何属性或方法?

可以拥有一个非泛型 Agent 基类,但它无法访问任何泛型属性或方法。

【讨论】:

  • 对不起。它是 LabState,FieldState。还有 LabAction、FieldAction。
  • LabState 和 FieldState 扩展 AState(AState 是一个抽象类)。
  • 没关系。事实上,具有不同泛型参数的类型是不同的类型。类型系统中有 一些 连接,但没有可以将两者都分配给的自动基本类型。
  • 好的,请将这些详细信息添加到您的问题中,包括Agent 的定义和类型。您也许能够使用协方差,但没有定义就不清楚了。
  • 如果您只是使用Object,那么首先使用泛型没有任何好处。
【解决方案2】:

您似乎想使用协方差。为了做到这一点,首先你需要一个Agent 将实现的接口,我们称之为IAgent。然后你需要像

一样定义那个接口
public interface IAgent<out TState, out TAction> 
    where TState : IState
    where TAction : IAction

那你就可以了

IAgent<IState, IAction> agent = new Agent<LabState, LabAction>

假设您的AgentLabStateLabAction 分别实现IAgentIStateIAction。但是,如果 IAgent 只返回这些类型的值并且从不接受它们,那么您只会将其定义为协变体。所以泛型类型应该只显示为方法的返回类型和只读属性的类型。您也可以用基类替换接口IActionIState,但协方差运算符out 只能用于接口。

【讨论】:

  • 其实,我的 LabState 和 LabAction 就是这样做的。我有一个抽象类 AState 和一个抽象类 AAction。 LabState 扩展了 AState,LabAction 扩展了 AAction。检查我在上述答案中的最后一条评论,解释了我尝试过的内容。
【解决方案3】:

你没有。

我认为你最好创建两个 UI 类,一个用于每种类型的代理,它们都派生自提供所有 UI 非代理功能的同一个基类。

【讨论】:

  • 如果是这样,泛型将毫无用处。我只有 2 种状态和动作,但我希望能够添加更多,所以如果我想这样做,我需要为每对新的状态和动作制作另一个 UI?重用代码不太好。
  • 如果所有的 UI 实例都只是创建一个新的代理,而所有其余的工作都在基 UI 类中完成 - 这是完全合理的代码重用。
  • 我有我的用户界面。 UI 使用控制器,控制器有一个 repo,repo 需要在构造函数中指定一个代理(专门的代理)。因此,如果我使用泛型,我只能更改代理的类型,而不是整个应用程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-02
  • 2022-12-17
  • 2013-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多