That's a pretty elementary question, but I have never delved into generics before and I found myself in the need to use it. Unfortunately I don't have the time right now to go through any tutorials and the answers I found to related questions so far aren't what one could call basic, so there we go:
Let's say I have the following:
List<MyClass1> list1 = getListType1();
List<MyClass2> list2 = getListType2();
if (someCondition)
MyMethod(list1);
else
MyMethod(list2);
And of course
void MyMethod(List<T> list){
//Do stuff
}
Well, I thought it would be this simple, but apparently it is not. VS warns me that
The type arguments for method MyMethod(System.Collections.Generic.List) cannot be inferred from the usage
and if I compile it anyway, I get a
The type or namespace name 'T' could not be found
error.
In the many answers I found, I read that I have to declare what T is, which makes sense, but I couldn't quite grasp how to do so in such a simplistic scenario. Of course, those answers created even more questions in my mind, but right now I just want an explanation of what I'm doing wrong (besides not studying generics) and how to make it right.
You need to declare T against the method, then C# can identify the type the method is receiving. Try this:
void MyMethod<T>(List<T> list){
//Do stuff
}
Then call it by doing:
if (someCondition)
MyMethod(list1);
else
MyMethod(list2);
You can make it even stricter, if all classes you are going to pass to the method share a common base class:
void MyMethod<T>(List<T> list) where T : MyClassBase
You need to add the generic type parameter for T to your method:
void MyMethod<T>(List<T> list) {
The compiler doesn't know what T represents, otherwise.
You need to let c# know what type is sent:
List<MyClass1> list1 = getListType1();
List<MyClass2> list2 = getListType2();
if (someCondition)
MyMethod<MyClass1>(list1);
else
MyMethod<MyClass2>(list2);
void MyMethod<T>(List<T> list){
//Do stuff
}
Basically, In C#, List < T > class represents a strongly typed list of objects that can be accessed by index.
And it also supports storing values of a specific type without casting to or from object.
we can use in Interger value & String Value in the List.
Related
My application uses
var results= websiteDetail.Detail.GetProductDetails<MyProduct>(code, websiteDetail.Detail.NegativeWords);
which in turn now calls
public List<T> GetProductDetails<T>(string websiteHtmlCode, List<string> negativeWords)
{
List<T> result = new List<T>();
foreach (var item in GetProducts(negativeWords))
{
result.Add((T)Convert.ChangeType(item, typeof(T)));
}
return result;
}
private List<MyProduct> GetProducts(List<string> negativeWords)
{
// logic
}
However, if I update the code to:
public List<T> GetProductDetails<T>(string websiteHtmlCode, List<string> negativeWords)
{
return GetProducts(negativeWords); //ERROR
}
I get told off with:
Cannot implicitly convert type 'System.Collections.Generic.List<MyProduct>' to 'System.Collections.Generic.List<T>
I then updated the code, to remove the List to work with single objects, the same issue persists.
Why do I have to call the ListConvert.ChangeType when the T is already of that type?
The problem here lies in understanding how C# generics work.
In C++, there was a concept of template specialization. That is, you could write:
void Foo<T> {}
void Foo<int> {}
If T was an int, it would use the specialized version, otherwise the generic. This is NOT allowed in C# generics. Either everything is generic, or everything isn't. When you write
public List<T> GetProductDetails<T>(string websiteHtmlCode, List<string> negativeWords)
You are now in the land of generics (albeit a generic method instead of class). Because you are now in the land of generics, making a call to a specific function:
List<MyProduct> GetProducts
Doesn't make any sense. What if T was object, or String? Returning a list of MyProduct would be very confusing, and almost assuredly fail when trying to cast (as your "working" code does). In other words, if you are always returning a List<MyProduct>, why bother with the generic (hence my earlier comment, they need to all be generic, or all concrete, you can't mix!).
The general rule of generics is "T is an object". That is all it is, and all it ever can be. If you need more specialization than just object, you need to add a where clause to your generic type argument. I kind of doubt you actually need that in this case, since you it looks like you are just doing a web request. You should be able to just change your function to:
List<T> GetProducts
At this point you may want to consider making the class generic as well, but that is up to you. If you can't make that change, I would remove the genericness from your method. You could do a switch on the type oF T but that isn't any better, and is very hard to understand/read.
MSDN for generic type constraints (where): MSDN
Please let me know if I can clarify anything!
I'm getting this message from ReSharper. ReSharper is not proposing the change that I think would be appropriate after examining the code. As a result I am concerned that the problem might might be my not understanding what's going on instead of ReSharper not being as helpful as it could be.
public interface IFrobable { }
public class DataClass
{
public List<IFrobable> Frobables {get; set;}
//...
}
public class WorkerClass
{
//...
void Frobinate(List<IFrobable> frobables)
{
//Frobs the input
}
void DoSomething(List<IFrobable> input>)
{
//Original code with Resharper on OfType<IActivity>
Frobinate(input.OfType<IFrobable>().ToList());
//Suggested change from ReSharper - Is this a generic refactor
//instead of issue specific?
Frobinate(Enumerable.OfType<IFrobable>(input).ToList());
//What I think should be safe to do - compiles and appears to work
Frobinate(input);
}
}
Is there any reason why my proposed change might not be safe.
This is a regular function call:
Enumerable.OfType<IFrobable>(input)
This is the same function but invoked as an extension method:
input.OfType<IFrobable>()
In your case:
Frobinate(input);
Is absolutely fine because:
input.OfType<IFrobable>().ToList()
Equals to:
input.Where(x => x as IFrobable != null).ToList()
And in you method input is already defined as List<IFrobable> so what's the point?
Your last case may or may not introduce a logic error.
Do you really want Frobinate the ability to modify the input list passed into DoSomething or just a copy of those references?
//Suggested change from ReSharper
Actually, invoking OfType as a static method on Enumerable rather than as an extension method on input is not a suggestion from ReSharper - it's a context action. I expound on the difference in this post.
To the actual issue:
The inspection
Redundant 'IEnumerable.OfType<T>' call. Consider comparing with 'null' instead
is not one that ReSharper offers a quick fix solution with, I guess since there isn't a single unambiguously 'correct' change to make. It's just saying
hey, everything in input is definitely going to be of type IFrobable - if you're trying to filter this list you might have meant to be filtering by nullness instead
This probably isn't relevant in your case.
As to your proposed fix - as already noted, this will mean passing the actual List<> reference given to DoSomething to Frobinate, rather than a new List<> containing the same items - if this is OK, then go for it.
in your example you have input which already consists of elements of type IFrobable so ReSharper says that it doesn't make sense to filter them by type IFrobable because the filter condition is always true it proposes you to use just input.ToList() invocation or to filter elements buy nullness: input.Where(element => element != null).ToList()
casting a var type objects to array of a class.
in my example I can query from the table all elements. but the problem is when i cast it, it just doesnt cast all instances.
any help??
There's no such type as "a var type". A declaration using var just makes the compiler infer the type of the variable. It's still statically typed, and works as if you'd explicitly declared it - although it allows you to declare variables which use an anonymous type.
In your case we don't know what any of the methods involved do, which means we can't really tell what's going on. It sounds like Query is probably of type IEnumerable<AccessPointItem>. You'll need to express in code how to convert from an AccessPointItem to an AccessPoint.
A few points to note:
Your query expression is somewhat pointless - you probably just want to call tsvc.CreateQuery<AccessPointItem>()
Conventionally, local variables in C# use camel casing (starting with lower case letters) not Pascal case
You create an array for no purpose - why?
Select() will never return null, so you don't need to check for it
Calling Cast will attempt to just cast each AccessPointItem to AccessPoint... is that really what you intended?
It looks as though you're you're mixing up your classes AccessPoint and AccessPointItem. Try this:
public static AccessPoint[] getAllAps()
{
return tsvc.CreateQuery<AccessPoint>("AccessPointTable").ToArray();
}
or this:
public static AccessPointItem[] getAllAps()
{
return tsvc.CreateQuery<AccessPointItem>("AccessPointTable").ToArray();
}
There is something wrong with the types involved.
First you read AccessPointItem:
var Query = from APs in tsvc.CreateQuery<AccessPointItem>(...)
Then you try to cast it to AccessPoint:
return Query.Cast<AccessPoint>()
You're gonna need to implement some kind of conversion method in order for that to work (unfortunately I never did it myself, but from a quick Google run I see plenty of info about the subject is available). I'll give it a shot off the top of my head:
//inside AccessPointItem.cs
public static AccessPoint ToAccessPoint(this AccessPointItem item) // extension method looks good for the job
{
AccessPoint retObj = new AccessPoint();
// assign properties from 'item' to 'retObj'
return retObj;
}
//Usage example in your case
return Query.Select(singleAccessPointItem => singleAccessPointItem.ToAccessPoint());
Afternoon, evening... whatever it is where you are ;)
I'm working on a 'ThreadManager' that will execute a set of 'ManagedThread<>'s. A managed thread is a generic wrapper for a 'ManagableThread', which contains most of the essential methods.
The list of 'ManagableThread's to start up, is based on what comes out of a configuration file, and is generated in the ThreadManager.Start method. This list, is meant to be populated with all of the 'ManagedThread's that are to be... managed. Here is the code that I am trying to use to complete this task, and as I'm sure any competent C# developer will quickly realize - I'm not gonna swing it like this.
public void Start() {
foreach (String ThreadName in this.Config.Arguments.Keys) {
Type ThreadType = null;
if ((ThreadType = Type.GetType(ThreadName)) == null) {
continue;
}
else {
ManagedThread<ThreadType> T = new ManagedThread<ThreadType>(
this,
this.GetConfiguration(ThreadType)
);
this.ManagedThreads.Add(T);
continue;
}
}
}
I've taken a few stabs at this to no avail. If anyone has any suggestions I'd appreciate them. I'm no Generics expert, so this is slightly out of my realm of expertise, so please do refrain from making me cry, but feel free to catch me if I'm a fool.
Thanks in advance to anyone who can offer a hand.
Edit: I suppose I should clarify my issue, rather than make you all figure it out... This code will not compile as I cannot pass 'ThreadType' to the generic parameter for my constructor.
That doesn't make sense.
Generics are compile-time types; you can't have a compile-time type that isn't known until runtime.
Instead, you need to use Reflection:
Type gt = typeof(ManagedThread<>).MakeGenericType(ThreadType);
object t = Activator.CreateInstance(gt, this,this.GetConfiguration(ThreadType));
This isn't possible. Generic parameters must be known at compile time. Your type isn't known until runtime.
I am working with the static method
Enum.GetValues(typeof(SomeEnum));
This method works great when all you need to do is enumerate the values, but for some reason it returns a very simple form of the Array class. I am trying to find an easy way to turn it's return value into a more "normal" collection class like a regular array or List<>.
So far if I want to do that I have to enumerate through the output of Enum.GetValues(typeof(SomeEnum)); and add them one by one to a List<>.
Any ideas how to do this more cleanly?
Answer:
The key is to cast the return result --
SomeEnum[] enums = (SomeEnum[]) Enum.GetValues(typeof(SomeEnum));
If you need a List then jus wrap it in parenthesis and ToList it like so:
List<SomeEnum> list = ((SomeEnum[]) Enum.GetValues(typeof(SomeEnum))).ToList();
If you're using .NET 3.5, you can also use Cast<T> and ToList extension methods.
IEnumerable<SomeEnum> enums = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();
You can also get a list if you want to
List<SomeEnum> list = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList();
Inspired by Jon Skeet's unconstrained-melody, I came up with version I like more:
public static class Enum<T>
where T: struct
{
static Enum()
{
Trace.Assert(typeof(T).IsEnum);
Values = Array.AsReadOnly((T[])Enum.GetValues(typeof(T)));
}
public static readonly ReadOnlyCollection<T> Values;
}
and usage:
var values = Enum<BindingFlags>.Values;
Good thing is this version works faster for multiple calls because it does not create new array on every time.
I found here you can just do this:
SomeEnum[] enums = (SomeEnum[]) Enum.GetValues(typeof(SomeEnum));
And if you need a List just use .ToList() at the end, like this:
List<SomeEnum> list = ((SomeEnum[]) Enum.GetValues(typeof(SomeEnum))).ToList();
Or if you like this better:
List<SomeEnum> list2 = new List<SomeEnum>((SomeEnum[]) Enum.GetValues(typeof(SomeEnum)));
I have a brand new library (UnconstrainedMelody) which helps with this. It can return the values in a strongly typed array or in an immutable list:
SomeEnum[] array = Enums<SomeEnum>.GetValuesArray()
IList<SomeEnum> list = Enums<SomeEnum>.GetValues();
It's generic and has a constraint on the type parameter to make sure it's genuinely an enum. This isn't possible in normal C#, but the library does a bit of furtling to make it work. I like the second form more, because we cache the list - the fact that it's immutable means we can return the same reference again and again.
There are various other utility methods to make it easier to work with flags enums etc.
Enjoy.
This should work:
List<MyEnum> enums = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).ToList();
The reason ToList() didn't work in the solution you posted in your question was that you're missing a set of parens around the casted portion. Hope this helps!
REVISION (12-Sep-2009 ~2:20 PM EST):
So, I made this suggestion last night on the basis that Enum.GetValues returns an Array, and I thought that Array implements IEnumerable<T>:
I believe you can construct a
List<T> passing any IEnumerable<T>
as a parameter into the constructor.
So you should be able to just do this:
List<SomeEnum> values = new List<SomeEnum>(Enum.GetValues(typeof(SomeEnum)));
However, GordonG quite promptly replied to my answer indicating that it doesn't compile. (Ordinarily I would test my answer, but I was at a computer without any development tools at the time and was also feeling quite [unreasonably] sure of myself.)
After some downvotes and heavy soul-searching I resolved to get to the bottom of this matter (after a good night's sleep). Turns out, according to Microsoft's documentation on the Array class here, that Array does implement IEnumerable<T>, but only at run time (so, not at compile time--hence the failure to compile). This, in hindsight, makes sense: Enum.GetValues is not a generic method, and so it cannot know what sort of generic collection to return beforehand. (At least that's how I understand it.)
Anyway, what this all means is that you can legally cast an Array to an IEnumerable<T> provided that you get your type right. And so, at last I can present my final answer, which is really the same as my original answer but with a simple cast thrown in to make everything legal:
// splitting into two lines just for readability's sake
List<SomeEnum> values;
values = new List<SomeEnum>((IEnumerable<T>) Enum.GetValues(typeof(SomeEnum)));
Of course, in retrospect, GordonG wasn't dead set on getting a List<T>, which means his own answer of casting to SomeEnum[] is really just as good.
Updated solution (from 'Konstantin Spirin') for .NET framework 2.0:
public static class Enum<T> where T : struct
{
static Enum()
{
Trace.Assert(typeof(T).IsEnum);
}
public static ReadOnlyCollection<T> Values = new ReadOnlyCollection<T>(((T[])Enum.GetValues(typeof(T))));
}
How about this:
List<SomeEnum> list = new List<SomeEnum>();
foreach (SomeEnum value in Enum.GetValues (typeof (SomeEnum)))
{
if (condition)
list.Add(value);
}