C#泛型函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/642933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 11:30:25  来源:igfitidea点击:

C# Generics function

c#generics

提问by DotnetDude

Can someone explain this behavior in Generics?

有人可以在泛型中解释这种行为吗?

I have a generic function in C#

我在 C# 中有一个通用函数

protected virtual void LoadFieldDataEditor <T> (ref T control, string strFieldName) where T : Control
{
  //T can be different types of controls inheriting from System.Web.UI.Control
  if (control is TextBox)
  {
   //This line gives an error
   //((TextBox)control).Text = "test";

   //This line works! 
   (control as TextBox).Text = "Test";
  }
}

On a side note, can I use switch case when I am doing a "Control is TextBox" type of checking?

附带说明一下,当我进行“控件是文本框”类型的检查时,我可以使用 switch case 吗?

EDIT:

编辑:

Forgot to add the error message Sorry!

忘记添加错误信息 抱歉!

Here you go:

干得好:

Error   3   Cannot convert type 'T' to 'TextBox'

EDIT:

编辑:

While we are talking about generics, I have another question. (Wasn't sure If I had to start a new post)

当我们谈论泛型时,我还有另一个问题。(不确定是否必须开始新帖子)

The method has been expanded to include another generic type

该方法已扩展为包括另一种泛型类型

protected virtual void LoadFieldDataEditor <T1, T2> (T1 control, T2 objData, string strFieldName) where T1 : Control where T2 : BaseDataType
{
  //I will need to access field1. 
  //I don't know at compile time if this would be SomeType1 or 
 //SomeType2 but all of them inherit from BaseDataType. 

  //Is this possible using generics?
}

public abstract class BaseDataType {}

public class SomeType1 : BaseDataType
{
   string field1;
   string field2;
}

采纳答案by Jon Skeet

The rules for what a generic type can be converted to are quite tricky, and occasionally counterintuitive, as in this case. See section 6.2.6 of the C# spec for details. There are places where they could be laxer, and I think this is one of them. You cancast up to objectand then down again, but that's ugly.

泛型类型可以转换为什么的规则非常棘手,有时甚至违反直觉,就像在这种情况下一样。有关详细信息,请参阅 C# 规范的第 6.2.6 节。有些地方他们可以更宽松,我认为这是其中之一。你可以向上object然后再向下施放,但这很丑陋。

In this case the better solution would be:

在这种情况下,更好的解决方案是:

protected virtual void LoadFieldDataEditor <T> (ref T control,
                                                string strFieldName) 
    where T : Control
{
    TextBox textBox = control as TextBox;
    if (textBox != null)
    {
        textBox.Text = "test";
    }
}

Aside from anything else, this only requires a single execution time check instead of two.

除此之外,这只需要一次执行时间检查而不是两次。

For the side note: no, you can't use switch/case on types. (You could get the type name and switch on that, but it would be horrible.)

附注:不,您不能在类型上使用 switch/case。(您可以获取类型名称并打开它,但这会很糟糕。)

回答by RossFabricant

The first line gives the compiler error: "Cannot convert type T to TextBox." That kind of cast is only legal if the compiler can know that it is possible to convert the starting class to the ending class. Because T could be anything, there's no way for the compiler to know. Even though you're checking at runtime this doesn't appease the compiler. The second kind of cast is OK, because it will just return null if the cast doesn't work. EDIT: As tuinstoel points out, the rules for casting are more complicated than I described.

第一行给出编译器错误:“无法将类型 T 转换为 TextBox。” 只有当编译器知道可以将起始类转换为结束类时,这种类型转换才是合法的。因为 T 可以是任何东西,编译器无法知道。即使您在运行时进行检查,这也不会让编译器感到满意。第二种类型转换是可以的,因为如果转换不起作用,它只会返回 null。编辑:正如 tuinstoel 指出的,铸造规则比我描述的要复杂。

回答by tuinstoel

In response to @rossfabricant.

回应@rossfabricant。

It is not so simple, the first method does compile, the second not.

没那么简单,第一种方法可以编译,第二种方法不能。

void Test(Control control)
{
    if (control is TextBox)
    {
       ((TextBox)control).Text = "test";
    }
}

void Test<T>(T control) where T : Control
{
    if (control is TextBox)
    {
        ((TextBox)control).Text = "test";
    }
}

回答by Reed Copsey

I'd highly recommend refactoring this to be:

我强烈建议将其重构为:

protected virtual void LoadFieldDataEditor(Control control, string strFieldName) 

As mentioned in a few comments, this method does not need generics at all.

正如一些评论中提到的,这个方法根本不需要泛型。

Since you're constraining to a Control, you know the base class, and it's a reference type (Control), so you can avoid the generics and the ref parameter declaration.

由于您限制为 Control,您知道基类,并且它是一个引用类型 (Control),因此您可以避免使用泛型和 ref 参数声明。

Since Control is a reference type, you are free to change it's properties in the method, and this will work correctly. Setting .Text, etc, will do exactly what you are trying to do, but be much simpler.

由于 Control 是一种引用类型,您可以在方法中自由更改它的属性,这将正常工作。设置 .Text 等将完全按照您的要求执行,但要简单得多。

There is a small chance that you could need it to be:

您可能需要它的可能性很小:

protected virtual void LoadFieldDataEditor(ref Control control, string strFieldName) 

but this would only be required if you were going to reassign control inside your method (ie: control = new TextBox();). I would strongly recommend against doing that, as it can cause some very unexpected behavior and would not be obvious. If you are trying to create a new control, using an out parameter, or just returning the new control would make everything much more clear.

但这仅在您要在方法中重新分配控制权时才需要(即:)control = new TextBox();。我强烈建议不要这样做,因为它会导致一些非常意外的行为并且不会很明显。如果您正在尝试创建一个新控件,使用 out 参数或仅返回新控件将使一切变得更加清晰。

Also, in general, it's a good idea to avoid generic methods unless there is a good reason to include them. The FxCop team has added (and later removed) some rules trying to discourage their use because they tend to make code less understandable in the long run. There are many good reasons for using generic methods, but this doesn't require their use, so I would recommend avoiding them.

此外,一般来说,避免使用泛型方法是个好主意,除非有充分的理由包含它们。FxCop 团队添加了(后来删除了)一些试图阻止它们使用的规则,因为从长远来看,它们往往会使代码更难理解。使用泛型方法有很多很好的理由,但这并不需要它们的使用,所以我建议避免使用它们。