C# 泛型和方法
Posted
技术标签:
【中文标题】C# 泛型和方法【英文标题】:C# Generic and method 【发布时间】:2008-11-18 20:16:57 【问题描述】:我怎样才能选择好的方法(我在下面的示例中显示了 2 种不同的方法不起作用)。我使用而不是带有 IF 和 IS 的 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);
它有效...为什么?
而且...我不能为所有类型重载执行方法,因为此方法来自接口。这就是为什么所有都需要从这个方法中调用。
【问题讨论】:
对象没有装箱和拆箱——它不是一个值类型。我只是删除泛型或重载方法 对象到真实类型......在将真实类型操作到对象之后...... 无论如何都没有拳击。这里没有值类型,因此没有装箱。 它是一个真实的对象--->以对象类型操作数据的解析器---->返回真实的对象。我看到一些从真实对象到对象的转换,而不是从对象到真实对象到过程的转换(对于这个问题,代码有点 sn-p)。所以是的,它确实有一些装箱/拆箱。 csharphelp.com/archives/archive100.html 一些装箱/拆箱参考。 【参考方案1】:不,你不能这样做。泛型不像 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
如果不进一步了解您想要做什么,很难说出最佳的方法。
【讨论】:
这个例子以很小的方式展示了我尝试做的事情。 Parser 类有很多私有方法,这些私有方法由执行方法调用,具体取决于对象类型。它需要重定向到好方法。 考虑使用从类型到委托的映射来调用。见***.com/questions/298976/… 这更多的是我搜索的我想,你如何设置地图?带有你考虑过接口吗?
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 编辑:
此解决方案需要更改所有业务逻辑对象以具有此接口。这真的不是一件事情(在我的情况下)。而且,在其他情况下,我总是更喜欢干净的 BusinessObject 没有与业务无关的接口。在我的问题中,我想要一个与 Generic/Object/Delegate 方法更相关的解决方案来实现它。谢谢你。此答案将不被接受。
【讨论】:
是的,但我不能为此做 100 课......我必须告诉你,我们这里有很多方法,因为它是数据库对象构建器。是的,我考虑过,但我想将所有数据库对象构建在同一个类中 而且我不会将所有的 BusinessLogic 都更改为 IAction ...这个选项确实不适合这种情况。 很公平......不过,这听起来像是一个界面的工作。如果您不考虑接口的唯一原因是您有很多方法和类要修改,那么您可以编写一个脚本来为您自动化该过程:) 该类需要完成其工作而不是加载它或其他任务(这样,如果我们更改加载方式或其他方法,业务对象不会受到影响。我不相信在这种情况下需要一个接口,但需要很多(您的代码的方式非常适合其他目的)【参考方案3】:类 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】:我没试过,但是你能做到吗?
罢工>
public T execute<T>(T obj)
this.action((T)obj);
return obj;
(根据cmets,不行)
或
public T execute<T>(T obj)
this.action(obj as T);
return obj;
(根据cmets,作品)
【讨论】:
没必要,“obj”已经是T类型了,不需要强制转换。 如果“as”遵循真实类型而不是 T(哎呀,我没有很好地阅读我认为的解决方案),则第二个工作。所以它有效,但我仍然需要做很多 IF...【参考方案5】:我知道您担心装箱/拆箱,所以这里可能涉及到 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。
【讨论】:
代码是这样的,因为有时我们从缓存中获取数据(反序列化)并且我们有一个新的引用,这就是我们需要返回的原因。我们需要通过参数传递对象来知道要加载哪个对象……你明白了吗? 不管数据来自缓存还是蒙古,如果任何类型都是值类型,你就会遇到传值问题。【参考方案6】:泛型发生在编译时。当您希望将相同的代码应用于不同的类型时,最好使用它。它不是动态的,因此无法帮助您根据输入类型在方法之间切换。
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;
它可能有点脆弱,但它在示例中有效。
【讨论】:
【参考方案7】:IIRC 您可以使用“where”子句来允许这样做
public T execute<T>(T obj) where : /* somthing */
我总是要自己用 Google 搜索那个,所以我会留在那里。
编辑:阅读一些 cmets。我不建议调用类型特定的代码。而是将该代码放在一个虚函数中并调用它。调用签名可能会很长,但这就是自动完成的目的。
Koodos to joshua.ewer for finding the man page
【讨论】:
如果有人在谷歌上搜索信息,这些被称为约束。可以基于类型、继承或实现等进行约束msdn.microsoft.com/en-us/library/d5x73970.aspx以上是关于C# 泛型和方法的主要内容,如果未能解决你的问题,请参考以下文章
C#语言中泛型和委托的关系是啥,Func<int>是泛型还是委托?
Java:Effective java学习笔记之 优先考虑泛型和泛型方法