C# 通用类型检查
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8941/
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
Generic type checking
提问by Rob Cooper
Is there a way to enforce/limit the types that are passed to primitives?(bool, int, string, etc.)
有没有办法强制/限制传递给原语的类型?(布尔、整数、字符串等)
Now, I know you can limit the generic type parameter to a type or interface implementation via the whereclause. However, this doesn't fit the bill for primitives (AFAIK) because they do not all have a common ground (apart from objectbefore someone says! :P).
现在,我知道您可以通过where子句将泛型类型参数限制为类型或接口实现。但是,这不符合基元(AFAIK)的要求,因为它们并非都有共同点(除了有人说之前的对象!:P)。
So, my current thoughts are to just grit my teeth and do a big switchstatement and throw an ArgumentExceptionon failure..
所以,我目前的想法是咬紧牙关做一个大的switch语句并在失败时抛出一个ArgumentException..
EDIT 1:
编辑 1:
Just to clarify:
只是为了澄清:
The code definition should be like:
代码定义应该是这样的:
public class MyClass<GenericType> ....
And instantiation:
和实例化:
MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)
EDIT 2
编辑 2
@Jon Limjap - Good point, and something I was already considering.. I'm sure there is a generic method that can be used to determine if the type is of a value or reference type..
@Jon Limjap - 好点,我已经在考虑的事情.. 我确定有一个通用方法可以用来确定类型是值还是引用类型..
This could be useful in instantly removing a lot of the objects I dont want to deal with (but then you need to worry about the structs that are used such as Size).. Interesting problem no? :)
这对于立即删除我不想处理的许多对象很有用(但是您需要担心使用的结构,例如Size).. 有趣的问题不是吗?:)
Here it is:
这里是:
where T : struct
Taken from MSDN.
摘自MSDN。
I'm curious.. Could this be done in .NET 3.x using extension methods? Create an interface, and implement the interface in the extension methods (which would probably be cleaner than a bit fat switch). Plus if you then need to later extend to any lightweight custom types, they can also implement the same interface, with no changes required to the base code.
我很好奇.. 这可以在 .NET 3.x 中使用扩展方法完成吗?创建一个接口,并在扩展方法中实现该接口(这可能比有点胖的开关更干净)。另外,如果您以后需要扩展到任何轻量级自定义类型,它们也可以实现相同的接口,而无需更改基本代码。
What do you guys think?
你们有什么感想?
Sad news is I am working in Framework 2!! :D
可悲的消息是我在框架 2 中工作!!:D
EDIT 3
编辑 3
This was so simple following on from Jon Limjaps Pointer.. So simple I almost want to cry, but it's great because the code works like a charm!
这是Jon Limjaps Pointer 的简单后续.. 如此简单我几乎想哭,但它很棒,因为代码就像一个魅力!
So here is what I did (you'll laugh!):
所以这就是我所做的(你会笑的!):
Code added to the generic class
添加到泛型类的代码
bool TypeValid()
{
// Get the TypeCode from the Primitive Type
TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));
// All of the TypeCode Enumeration refer Primitive Types
// with the exception of Object and Empty (Null).
// Since I am willing to allow Null Types (at this time)
// all we need to check for is Object!
switch (code)
{
case TypeCode.Object:
return false;
default:
return true;
}
}
Then a little utility method to check the type and throw an exception,
然后是一个检查类型并抛出异常的小实用方法,
private void EnforcePrimitiveType()
{
if (!TypeValid())
throw new InvalidOperationException(
"Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name +
"' - this Class is Designed to Work with Primitive Data Types Only.");
}
All that then needs to be done is to call EnforcePrimitiveType()in the classes constructors. Job done! :-)
然后需要做的就是在类构造函数中调用EnforcePrimitiveType()。任务完成!:-)
The only one downside, it only throws an exception at runtime (obviously) rather than design time.. But that's no big deal and could be picked up with utilities like FxCop(which we don't use at work).
唯一的缺点是,它只在运行时(显然)而不是在设计时抛出异常。但这没什么大不了的,可以用FxCop 之类的实用程序(我们在工作中不使用)来解决。
Special thanks to Jon Limjap on this one!
特别感谢 Jon Limjap 在这方面!
采纳答案by Jon Limjap
Primitives appear to be specified in the TypeCode
enumeration:
原语似乎在TypeCode
枚举中指定:
Perhaps there is a way to find out if an object contains the TypeCode enum
without having to cast it to an specific object or call GetType()
or typeof()
?
也许有一种方法可以确定一个对象是否包含 ,TypeCode enum
而不必将其强制转换为特定对象或调用GetType()
或typeof()
?
UpdateIt was right under my nose. The code sample there shows this:
更新它就在我的鼻子底下。那里的代码示例显示了这一点:
static void WriteObjectInfo(object testObject)
{
TypeCode typeCode = Type.GetTypeCode( testObject.GetType() );
switch( typeCode )
{
case TypeCode.Boolean:
Console.WriteLine("Boolean: {0}", testObject);
break;
case TypeCode.Double:
Console.WriteLine("Double: {0}", testObject);
break;
default:
Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
break;
}
}
}
It's still an ugly switch. But it's a good place to start!
这仍然是一个丑陋的开关。但这是一个很好的起点!
回答by Lars M?hlum
public class Class1<GenericType> where GenericType : struct
{
}
This one seemed to do the job..
这个似乎可以完成工作..
回答by JoshL
回答by Keith
Pretty much what @Lars already said:
几乎@Lars 已经说过:
//Force T to be a value (primitive) type.
public class Class1<T> where T: struct
//Force T to be a reference type.
public class Class1<T> where T: class
//Force T to be a parameterless constructor.
public class Class1<T> where T: new()
All work in .NET 2, 3 and 3.5.
所有工作都在 .NET 2、3 和 3.5 中运行。
回答by Doug McClean
If you can tolerate using factory methods (instead of the constructors MyClass you asked for) you could always do something like this:
如果您可以容忍使用工厂方法(而不是您要求的构造函数 MyClass),您总是可以执行以下操作:
class MyClass<T>
{
private readonly T _value;
private MyClass(T value) { _value = value; }
public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
// etc for all the primitive types, or whatever other fixed set of types you are concerned about
}
A problem here is that you would need to type MyClass<AnyTypeItDoesntMatter>.FromInt32
, which is annoying. There isn't a very good way around this if you want to maintain the private-ness of the constructor, but here are a couple of workarounds:
这里的一个问题是您需要键入MyClass<AnyTypeItDoesntMatter>.FromInt32
,这很烦人。如果你想保持构造函数的私有性,没有一个很好的方法来解决这个问题,但这里有几个解决方法:
- Create an abstract class
MyClass
. MakeMyClass<T>
inherit fromMyClass
and nest it withinMyClass
. Move the static methods toMyClass
. This will all the visibility work out, at the cost of having to accessMyClass<T>
asMyClass.MyClass<T>
. - Use
MyClass<T>
as given. Make a static classMyClass
which calls the static methods inMyClass<T>
usingMyClass<AnyTypeItDoesntMatter>
(probably using the appropriate type each time, just for giggles). - (Easier, but certainly weird) Make an abstract type
MyClass
which inherits fromMyClass<AnyTypeItDoesntMatter>
. (For concreteness, let's sayMyClass<int>
.) Because you can call static methods defined in a base class through the name of a derived class, you can now useMyClass.FromString
.
- 创建一个抽象类
MyClass
。使其MyClass<T>
继承MyClass
并将其嵌套在MyClass
. 将静态方法移至MyClass
. 这会将所有的知名度锻炼,在其访问的成本MyClass<T>
为MyClass.MyClass<T>
。 - 按规定使用
MyClass<T>
。创建一个静态类MyClass
,它在MyClass<T>
using 中调用静态方法MyClass<AnyTypeItDoesntMatter>
(可能每次都使用适当的类型,只是为了咯咯笑)。 - (更简单,但肯定很奇怪)创建一个
MyClass
从MyClass<AnyTypeItDoesntMatter>
. (为了具体起见,我们假设MyClass<int>
。)因为您可以通过派生类的名称调用基类中定义的静态方法,所以现在可以使用MyClass.FromString
.
This gives you static checking at the expense of more writing.
这为您提供了静态检查,但代价是更多的写入。
If you are happy with dynamic checking, I would use some variation on the TypeCode solution above.
如果您对动态检查感到满意,我会在上面的 TypeCode 解决方案上使用一些变体。
回答by Vivek
You can simplify the EnforcePrimitiveType
method by using typeof(PrimitiveDataType).IsPrimitive
property. Am I missing something?
您可以EnforcePrimitiveType
通过使用typeof(PrimitiveDataType).IsPrimitive
属性来简化该方法。我错过了什么吗?
回答by Matthew Boehlig
@Rob, Enum
's will slip through the TypeValid
function as it's TypeCode
is Integer
. I've updated the function to also check for Enum
.
@Rob,Enum
的会滑过TypeValid
,因为它的功能TypeCode
是Integer
。我已经更新了函数来检查Enum
.
Private Function TypeValid() As Boolean
Dim g As Type = GetType(T)
Dim code As TypeCode = Type.GetTypeCode(g)
' All of the TypeCode Enumeration refer Primitive Types
' with the exception of Object and Empty (Nothing).
' Note: must also catch Enum as its type is Integer.
Select Case code
Case TypeCode.Object
Return False
Case Else
' Enum's TypeCode is Integer, so check BaseType
If g.BaseType Is GetType(System.Enum) Then
Return False
Else
Return True
End If
End Select
End Function
回答by gimlichael
Having a similar challenge, I was wondering how you guys felt about the IConvertible interface. It allows what the requester requires, and you can extend with your own implementations.
遇到类似的挑战,我想知道你们对IConvertible 界面的看法。它允许请求者需要什么,并且您可以使用自己的实现进行扩展。
Example:
例子:
public class MyClass<TKey>
where TKey : IConvertible
{
// class intentionally abbreviated
}
I am thinking about this as a solution, all though many of the suggested was part of my selection also.
我正在考虑将此作为解决方案,尽管许多建议也是我选择的一部分。
My concern is - however - is it misleading for potential developers using your class?
但是,我担心的是 - 它是否会对使用您的课程的潜在开发人员产生误导?
Cheers - and thanks.
干杯 - 谢谢。