如何选择好方法(我在下面的例子中显示了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方法重载,因为这个方法来自一个接口。这就是为什么所有人都需要从这种方法中调用。
答案 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;
}
}
此解决方案需要将所有业务逻辑对象更改为具有此接口。这真的不是一件事(在我的情况下)。而且,在其他情况下,我总是喜欢使用没有与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支持我自己,所以我会留下它。
编辑:阅读一些评论。我不建议调用特定类型的代码。而是将该代码放在虚函数中并调用它。呼叫签名可能会变长,但这就是自动完成的目的。
答案 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;
}
它可能有点脆弱,但它可以在示例中使用。