【问题标题】:How do you provide a default type for generics?如何为泛型提供默认类型?
【发布时间】:2010-11-09 02:59:12
【问题描述】:

我有一个类,目前有几个采用整数参数的方法。这些整数映射到应用程序可以执行的操作。我想让类成为通用类,以便类的使用者可以提供他们拥有的枚举类型以及其中的所有操作,然后这些方法将采用该枚举类型的参数。但是,我希望他们能够根本不指定泛型类型,并将其默认返回为整数,而不改变当前方式的语法。这可能吗?

【问题讨论】:

  • @Vilx- 解决方案不是一个好方法和更好的答案吗?
  • @Max Schmeling 第一个答案发布后(我假设它被接受后)提供了正确答案。为了以后的搜索者的利益,请您接受正确的答案。
  • 所以我意识到这些问题来自很久以前......但这是重复的:stackoverflow.com/q/707780

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


【解决方案1】:

编译器大多数时候可以根据传递的参数类型推断方法的类型参数:

public void DoSomething<T>(T test) {
}

可以调用

DoSomething(4);                   // = DoSomething<int>(4);
DoSomething(MyEnum.SomeValue);    // = DoSomething<MyEnum>(MyEnum.SomeValue);

顺便说一句,您也可以对泛型方法进行非泛型重载。

【讨论】:

  • 我正在寻找具有“可选通用性”的类。我认为这是不可能的,所以我只需要使用非泛型重载来制作泛型方法......我一直在寻找这个“SecurityContext sec = new SecurityContext();” (它将使用整数作为参数创建它,然后“SecurityContext sec = new SecurityContext();”将使用 MyOperations 作为参数创建它
【解决方案2】:

保留您的原始版本(非通用版本)并创建它的通用版本。

然后从您的非通用版本中调用通用版本。

void Main()
{
DoSomething(2);
DoSomething(EnumValue);

}

public void DoSomething(int test) {
DoSomething<int>(test);
}

// Define other methods and classes here
public void DoSomething<T>(T test) {
Console.WriteLine(test);
}

【讨论】:

  • 所有方法的泛型参数类型都是相同的,所以我希望在类级别使用它。我知道我可以制作一个通用版本,然后从它继承 int 版本,但我只是希望将它全部整合在一起......但我不知道有任何方法可以做到这一点。我想这不可能像我希望的那样简单。
【解决方案3】:

在类的定义中不能这样做:

var foo = new MyGenericClass(); // defaults to integer... this doesn't work
var bar = new MyGenericClass<MyEnum>(); // T is a MyEnum

如果真的看重默认类型为 int 的隐含性,您将不得不使用静态工厂方法来完成,尽管我看不到它的价值。

public class MyGenericClass<T>
{
    public static MyGenericClass<T> Create()
    {
        return new MyGenericClass<T>();
    }
    public static MyGenericClass<int> CreateDefault()
    {
        return new MyGenericClass<int>();
    }
}

请参阅下文,了解您实际上如何无法从上述内容中受益。

var foo = MyGenericClass<MyEnum>.Create();
var bar1 = MyGenericClass.CreateDefault(); // doesn't work
var bar2 = MyGenericClass<int>.CreateDefault(); // works, but what's the point

如果你想更进一步,你可以创建一个静态工厂类来解决这个问题,但如果你这样做只是为了提供默认类型,那就更荒谬了:

public static class MyGenericClassFactory
{
    public static MyGenericClass<T> Create<T>()
    {
        return new MyGenericClass<T>();
    }
    public static MyGenericClass<int> Create()
    {
        return new MyGenericClass<int>();
    }
}

var foo = MyGenericClassFactory.Create(); // now we have an int definition
var bar = MyGenericClassFactory.Create<MyEnum>();

【讨论】:

  • 是的,我不想介绍那种复杂性。默认值不是非常重要,它会很好。我不知道有什么办法,但我想先和你们所有人核实一下。谢谢你的回答
  • 这个答案不完整 - 它错过了实现所需默认值的非常简单的方法。请参阅下面 Vilx- 的答案。
【解决方案4】:

那么...为什么不使用简单继承呢?喜欢:

class MyGenericClass<T>
{
}

class MyGenericClass : MyGenericClass<int>
{
}

这样你可以写两种方式:

var X = new MyGenericClass<string>();
var Y = new MyGenericClass(); // Is now MyGenericClass<int>

【讨论】:

  • 唯一可悲的是,这仅限于泛型类。如果拥有一个结构(很多)更有意义,那么似乎仍然没有方便的替代方案。
  • @Maxx - 好吧,您可以在要使用它的文件开头添加using ShortcutType = MyType&lt;int&gt;;。归根结底,这只是方便。
【解决方案5】:

我确定您已经从这里开始,但是我正在处理一个类似的问题,并发现这个解决方案使用了我不熟悉的“使用”上下文。他们需要把它放在他们的命名空间中,所以它并不完全完美。

namespace mygeneric
{
    public class SecurityContext<T>
    {

    }
}

namespace mytest
{
    using SecurityContext = mygeneric.SecurityContext<int>;
    using mygeneric;

    enum MyContexts
    {
        User,
        Admin
    }
    class MyTest
    {
        SecurityContext myDefaultContext;
        SecurityContext<MyContexts> mySpecialContext;
    }
}

【讨论】:

  • 这很酷,很可能会被用来作恶。 :-)
【解决方案6】:

编译器大部分时间可以根据传递的参数类型推断字段的类型参数:

import lombok.Data;

@Data
public class MyClass<T> {

    private T myField;
}

可以用作,

MyClass myClass = new MyClass();
String abc = "hello world !";
myClass.setMyField(abc);
System.out.println("test generic class with generic field = " + myGenericClass.getMyField());

这应该会导致,

test generic class with generic field = hello world !

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 2017-12-06
    • 1970-01-01
    相关资源
    最近更新 更多