I've ha开发者_运维知识库d my first foray into generics, and understand them a little bit. I have a method intended to accept two lists of any object, match them various ways and return the matched/unmatched objects (the stuff inside the method probably isn't key here). The purpose is to accept any kind of object, be it customers, or whatever. However, I've hit a snag with getting it to accept 'string', I'm guessing because it's not initialised with the new() keyword and isn't like a normal instanced class.
So, I have a method declaration like so:
public static compareResult<T> stepCompare<T>(List<T> leftList, List<T> rightList, Comparison<T> IDComparer = null, Comparison<T> lowLevelComparer = null, bool confirmUniqueness = true) where T : IComparable, new()
Admittedly, adding the where clause at the end was in response to an error "cannot create an instance of the variable type 'T' because it does not have the new() constraint". This appeared against a line in the method saying
T lastItem = new T();
However, now if I try to pass it two Lists<string>
, it says "'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'MF.Comparers.stepCompare<T>(System.Collections.Generic.List<T>, System.Collections.Generic.List<T>, System.Comparison<T>, System.Comparison<T>, bool)'
...
Any way to let this method accept lists whether they be of string or other classes? Or a shortcut to put lists of string into a type that will be accepted?
You can't make string
satisfy the new()
constraint, no. While string
is a normal class, and instances can be created using constructors in a perfectly normal way, it doesn't have a parameterless constructor.
The best approach really depends on why you had that line of code including lastItem
. If you just want some default value, then default(T)
is probably the best approach.
If you really do want to create a new instance of T
, then you should probably accept a Func<T>
in the method's parameter list, as a way of creating a default value on demand. Alternatively, if you're happy using a particular single value as the default, you could just add a parameter of type T
. It's hard to say without seeing the rest of your code.
If you want any object, you probably have to live without the new T()
. You could do the same with a combination of reflection, special-cases (for string
etc), and Activator.CreateInstance<T>()
- however, IMO you should limit yourself (in this case) to default(T)
, which will be null for reference types (including string) and nullable value-types, and all-zeros for non-nullable value-types. You should also probably use a bool
or similar to make sure you don't actually use that value, except to satisfy definite assignment rules for the compiler.
精彩评论