如何简化泛型方法中的条件?

时间:2017-05-16 13:37:41

标签: c# generics

我有一个通用方法$creds = Get-Credential $unsecureCreds = $creds.GetNetworkCredential() $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $unsecureCreds.UserName,$unsecureCreds.Password))) Remove-Variable unsecureCreds Invoke-RestMethod -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} ...

在方法内部,我需要根据T的实际类型采取具体行动:

public void DoAThing<T>(T inputData)

当我想出更多类型的动作时,如何保持if / else语句不断增长?用if (typeof(T) == int) { // Handle integer input. } else if (typeof(T) == string) { // Do something else. } else { // Default action. } 语句替换在语法上看起来更好,但是具有相同的底层问题:我必须添加越来越多的案例。

直觉上我明白切换必须在某个时刻完成,我只是在寻找一种更优雅的方式。

编辑:我得到的答案并不是我想要的,但这可能是因为我走错了路。我意识到我的原始问题已经解决,这可能是问题的一部分。

与我合作的方法实际上是:

switch

因此,我打开T的原因是因为该方法需要进行一些不同的处理才能获得返回值。在这种情况下,什么更有效:对每个预期类型使用if / else的泛型方法,或者只为每个有效返回类型使用一系列方法(public T void ReturnAThing<T>(string thingName)ReturnAString等等)?

3 个答案:

答案 0 :(得分:0)

或许(或许强调)你想要的是这样的东西。 (最后这个长期答案的底部解释了为什么你不应该这样做。但实验起来不错。)

public abstract class DoesSomething<T>
{
    public abstract void DoSomething(T input);
}

现在,您可以编写针对特定类型覆盖此内容的单个类:

public class DoesSomethingWithAString : DoesSomething<string>
{
    public override void DoSomething(string input)
    {
        // Do whatever
    }
}

正如评论中所提到的,如果您正在检查某些内容以查看其类型,则会出现问题。类型安全的一个好处是您只需要知道对象的声明类型。即使实际实例是从该声明类型继承的东西,您也不需要知道。如果参数显示为Foo,那么它就是Foo,这就是您需要知道的全部内容。

如果我们必须检查对象以确定它们的类型,那么一切都可能只是object,如下所示:

public class DoesSomething
{
    public void DoSomething(object input)
    {
        if(input is string)
        {
            // Do something
        }

        if(input is Foo)
        {
            // Do something
        }
    }
}

当泛型类没有“关心”时,泛型是有意义的。具体类型是什么,如List<T>。无论T是什么,它都会保留T的实例。或者您可以对其进行约束,如:

public class MyFooHandler<TFoo> where TFoo:Foo

确保泛型类型为Foo或继承自Foo。但在这种情况下,这些方法应该只关心&#34;它是Foo。如果你发现自己正在检查它是什么样的Foo,那么又出现了一些问题。

如果您的某个班级可能在int上运行,或者可能在string上运行,那么一个好问题是,为什么它需要是一个班级或一个方法,因为它可能会做两件完全不同的事情?也许应该有两个班级。也许应该有一个有多种方法的类。也许您只需要string方法,并且在调用方法之前应将您的整数转换为字符串。

有时候我们会被这些问题所吸引,因为我们正试图想办法让一个班级做很多不同的事情。当我们尝试使用泛型时,这种情况会发生很多。但通常答案是,如果我们做两件不同的事情,我们应该有两个班级。

即使在上面两个类继承自DoesSomething<T>的示例中,也很有问题,让这些类从一个基类继承有什么好处?通常没有任何好处,它只会在以后制造麻烦。最好开始写个别的课程,每个课程做一件小事或一些密切相关的小事。

答案 1 :(得分:0)

你应该这样做

public void DoAThing(int inputData)

public void DoAThing(string inputData)

答案 2 :(得分:0)

通过使用单一泛型方法,您允许调用者从中获得任何类型的返回值,但是您可以在方法中处理它吗?

此示例显示您可以轻松破坏能够处理任何返回类型的方法契约:

@SuppressWarnings("unchecked")
public <T> T returnAThing(String input){
    if (input.equals("a") ) return (T) new Integer(1);
    else if (input.equals("b") ) return (T)"ABC";
    else return null;
}    

@Test
public void test(){
  Integer result1 = returnAThing("a"); //ok result is 1
  Integer result2 = returnAThing("b"); //fails      
}

我认为你这里只有两个选择:

1)让您的方法获取Class实例,以便您可以知道调用者期望的返回类型。 ˚F

@SuppressWarnings("unchecked")
public <T> T returnAThing(Class<T> type, String input){
    if ( input.equals("a") && type.equals(Integer.class) ) return (T) new Integer(1);
    else if (input.equals("b") && type.equals(String.class) ) return (T)"ABC";
    else return null;
}    

@Test
public void test(){
  Integer result = returnAThing(Integer.class, "a");  //ok result is 1      
  result = returnAThing(Integer.class, "b"); //ok result is null
}

2)为每种返回类型设置单独的方法。

哪种方法对你更好?这取决于。如果您正在处理少数不同的返回类型,那么请使用单独的方法方法。