C#Generic和方法

时间:2008-11-18 20:16:57

标签: c# .net generics .net-2.0 c#-2.0

如何选择好方法(我在下面的例子中显示了2种不同的方法)。我使用IF而不是Object类型的变量来做这项工作,但我试图避免使用Object和装箱/拆箱。所以我认为Generic可以完成这项工作,但我被困在这里。

以下是一小段代码,用于说明我的问题:

class Program
{
    static void Main(string[] args)
    {
        Parser p = new Parser();
        ObjectType1 o1 = new ObjectType1();
        p.execute(o1);
        Console.Read();
    }
}

class Parser
{
    public T execute<T>(T obj)
    {
        /*
        if (obj is ObjectType1)
            this.action((ObjectType1)obj);
        else if (obj is ObjectType2)
            this.action((ObjectType2)obj);
        */
        this.action(obj);
        return obj;
    }

    private void action(ObjectType1 objectType1)
    {
        Console.WriteLine("1");
    }

    private void action(ObjectType2 objectType2)
    {
        Console.WriteLine("2");
    }
}


class ObjectType1
{
}

class ObjectType2
{
}

更新

我不想要接口和类。抱歉。我知道这不是问题的目标。

使用(ObjectType)obj进行转换不起作用,但如果你这样做:

        if (obj is ObjectType1)
            this.action(obj as ObjectType1);
        else if (obj is ObjectType2)
            this.action(obj as ObjectType1);

它有效......为什么?

并且......我不能为所有类型的execute方法重载,因为这个方法来自一个接口。这就是为什么所有人都需要从这种方法中调用。

7 个答案:

答案 0 :(得分:4)

不,你不能这样做。泛型不像C ++模板那样工作 - 泛型方法只编译一次。编译器可以用于重载解析的唯一信息是它在泛型方法中知道的信息,无论代码使用什么代码。

作为一个展示这个的例子,这里有一些代码可能无法按预期运行:

using System;

class Test
{    
    static void Main()
    {
        string x = "hello";
        string y = string.Copy(x);

        Console.WriteLine(x==y); // Overload used
        Compare(x, y);
    }

    static void Compare<T>(T x, T y) where T : class
    {
        Console.WriteLine(x == y); // Reference comparison
    }
}

如果不了解更多关于你想做什么的话,很难说最好的方法。

答案 1 :(得分:4)

您是否考虑过界面?

interface IAction
{
   void action();
}

class ObjectType1 : IAction
{
   void action() {
      Console.WriteLine("1");
   }
}

class ObjectType2 : IAction
{
    void action() {
      Console.WriteLine("2");
    }
}

class Parser
{
   public IAction execute(IAction obj)
   {
      obj.action();
      return obj;
   }
}

由OP编辑:

此解决方案需要将所有业务逻辑对象更改为具有此接口。这真的不是一件事(在我的情况下)。而且,在其他情况下,我总是喜欢使用没有与Business无关的Interface的干净BusinessObject。在我的问题中,我想要一个与Generic / Object / Delegate方法更相关的解决方案来实现它。求求你。这个答案将不被接受。

答案 2 :(得分:2)

我还没有尝试过,但你可以这样做吗?

<击>

<击>
public T execute<T>(T obj)
{
    this.action((T)obj);
    return obj;
}

<击>

(根据评论,不起作用)

public T execute<T>(T obj)
{
    this.action(obj as T);
    return obj;
}

(根据评论,作品)

答案 3 :(得分:2)

  

类Parser有很多私有方法,由execute方法根据对象类型调用。它需要重定向到好的方法。

编译器将为您完成此工作。只需使用重载。

class Parser
{
    public ObjectType1 action(ObjectType1 objectType1)
    {
        Console.WriteLine("1");
        return objectType1;
    }
    public ObjectType2 action(ObjectType2 objectType2)
    {
        Console.WriteLine("2");
        return objectType2;
    }
}

class ObjectType1 { }
struct ObjectType2 { }

然后,呼叫:

Parser p = new Parser();
p.action(new ObjectType1());
p.action(new ObjectType2());

没有装箱/拆箱,并且会调用相应的方法。

答案 4 :(得分:1)

我知道你担心装箱/拆箱,所以这里可能会涉及ValueTypes。

public T execute<T>(T obj)   
{        
    this.action(obj);
    return obj;
}

假设操作正在修改obj,并且还假设修改对调用者很重要(这就是为什么要将值返回给调用者)。这段代码有一个令人讨厌的传值值缺陷。

考虑以下代码:

    public int execute(int obj)   
    {        
        this.action(obj);
        return obj;
    }

    public void action(int obj)
    {
        obj = obj + 1;
    }

以这种方式打电话。

int x = p.execute(1);

x是1,而不是2。

答案 5 :(得分:0)

IIRC你可以使用“where”子句来允许这个

public T execute<T>(T obj) where : /* somthing */
{
}

我总是向Google支持我自己,所以我会留下它。

编辑:阅读一些评论。我不建议调用特定类型的代码。而是将该代码放在虚函数中并调用它。呼叫签名可能会变长,但这就是自动完成的目的。

Koodos to joshua.ewer for finding the man page

答案 6 :(得分:0)

泛型发生在编译时。当您希望将相同的代码应用于不同类型时,最好使用它。它不是动态的,因此根据输入类型不能帮助您在方法之间切换。

在David B的回复中重载解析有效,但也在编译期间发生。

更新中的代码执行相同的操作。它(在仔细检查类型之后)然后使用重载来解析方法。

我觉得你想根据运行时输入切换方法。

如果您使用了反射,则可以获得更加动态的行为。

        public object execute(object obj) 
        {
            MethodInfo m = typeof(Parser).GetMethod(
                "action", 
                BindingFlags.Instance | BindingFlags.NonPublic, 
                null, 
                new Type[] { obj.GetType() }, 
                null);
            m.Invoke(this, new object[] { obj });
            return obj; 
        } 

它可能有点脆弱,但它可以在示例中使用。