A colleague pointed me to a strange case in C# (not so sure if this actually strange though).
Suppose you have a class Employee. If you want to create a Generic List<> of type Employee, you can simply do:
List<Employee> x = new List<Employee>;
I understand that I need to pass the Employee type to the Generic list so that it knows the required type information about Employee and generates methods that return and accept parameters that are compatible with Employee.
Now my question is, why isn't it possible to do the following?
Employee x = new Employee();
List<typeof(x)> list = new List<typeof(x)>();
Shouldn't this suffice the information required for List<> to know, in order to create a list? In other words, the type of x which is the type of Employee is now passed as a generic type parameter to List<>, which (as I used to believe) is the same as passing list the type name (in this case Employee).
I know that something like this is available in Java (using the .class) keyword on a variable.
I'm sure I AM missing something, so please, enlight me guys!
No, the equivalent of that isn't available in Java. You can't use "x.class" to get at the declared type of a variable.
Moreover, typeof(x) doesn't work in C# either to get the type of a variable - it returns a Type reference for the type name, e.g. typeof(string) will return a reference to the Type object associated with the System.String type. That's equivalent to using String.class in Java. (Note that again, that's applying .class to a type name, not a variable name.)
Java generics don't support anything like your final statement either. If you believe they do, please give a sample :)
What you can do in C# is use type inference to do what you want:
public static List<T> CreateListForSampleType<T>(T sample)
{
return new List<T>();
}
...
Employee x = new Employee();
var list = CreateListForSampleType(x);
Note that there's no reason why C# couldn't be extended to allow something like typeof(variablename) or List<typeof(variablename)> - it's all compile-time type information, after all. However, I can't see that it would meet the team's requirements for usefulness... there are other far more useful features I'd like to see first :)
The reason for this is that typeof() returns a type object, while you need a type name to initialize a list at compile-time.
One part of the answer is that the type of x is not available at compile time, i.e. it might be created using something like this:
Employee x = EmployeeFactory.NewEmployee("John Doe"); // Returns TraineeEmployee, Employee or ManagementEmployee;
List<typeof(x)> l = new List<typeof(x)> l(); // What type is it?
You can however create a List of a base class of what you want to store in the list (or even a List of "object"s).
typeof is used with class names. Use GetType() on an object, but only at runtime...
What you are missing - imho - is the difference between a static type reference at compile-time and a dinamyc type reference (via an instance of System.Type) at run-time.
typeof() and .GetType() give you the latter. (for types and instances, respectively)
I hope it makes clear.
Jon Skeet's code above is cool.
Can't find a reason to create an empty list since C# 3.0.
I generally create list instances only with a ToList method from an IEnumerable, which is in turn generated using a yield return, Concat(), Repeat(), Where() etc.
var list = CreateEmployees().ToList();
,
public IEnumerable<Employee> CreateEmployees()
{
yield return new Employee("Foo");
yield return new Employee("Bar");
}
Related
This question already has answers here:
How can I return an anonymous type from a method?
(4 answers)
Closed 9 years ago.
I have some sub queries which are of data type var. These are getting working on a data table. I would like to pass these into another method, how can i do that?
Ex:
var subquery1= from results in table.AsEnumerable()
where //some condition
select new
{
column1=results.field1,
column2 = results.field2
etc.,
}
var subquery2= from results in table.AsEnumerable()
where //different condition
select new
{
column1=results.field1,
column2 = results.field2
etc.,
}
Now, I would like to define some method to pass these subquery1, subquery2 as variables.
ex:
void updategrid(var queries)
{
//some logic
}
And execute the method:
updategrid(subquery1);
updategrid(subquery2);
When i try to use var in the method when defining it is not liking it. Please help me in how to do that.
Thanks.
Your result is a sequence of anonymous objects. var Keyword is just saying to compiler "Hey, deduce arguments for me from usage". The process of deducing types from usage is called Type Inference. But you can't say to C# compiler to infer types of method arguments in method declaration. Moreover, in case of anonymous objects you cant specify their name. So you shouldn't pass them around outside and inside other methods. You can cast them to dynamic and then access their members via CallSite (compiler creates them when you access a member of dynamic object like myDynamic.Name) or you can cast anonymous object to object and access its properties via reflection, but all these methods are non C# idiomatic and really miss the point of anonymous objects.
Instead of creating anonymous objects in query
select new
{
//members selection
}
Create a custom type
public class Result
{
//Members declaration
}
And instantiate it as the result of query like in next example: (you can substitute var keyword instead of IEnumerable<Result> - compiled code will be the same)
IEnumerable<Result> subquery1 = from results in table.AsEnumerable()
where //some condition
select new Result
{
//fill members here
}
Method will look like
void updategrid(IEnumerable<Result> queries)
{
//some logic here with strongly typed sequence
}
Then you will call updategrid like simply updategrid(subquery1) and you will have all the beauty of statically typed sequence of your elements in the body of updategrid
You can declare method with var type of argument. But you can write so:
static void updategrid(dynamic queries)
{
}
var means take type from right-hand side and declare variable with this type from left-hand side and this is processed in compile-time. As you can seen using var as method argument type makes no sense.
void updategrid(var queries)
Is not valid C#.
var is syntactic sugar - the variable has a type, but you don't need to declare it if the compiler can statically determine what it should be.
With a parameter, the compiler doesn't have enough information to determine the type.
Similarly, you can't declare a variable with var without assignment:
var something;
You will need to ensure the types of subquery1, subquery2 and the parameter to updategrid are all the same.
Var is not a data type. It is short hand for "figure out what data type this actually is when you compile the app". You can figure out what the data type actually is and use that for your parameter or you could create a generic function that will work with any data type.
Use Object or dynamic
void updategrid(object queries)
void updategrid(dynamic queries)
var -> static type that is determined by the right side of expression. Cannot be used as parameter/return type
object -> Base class for all .NET types.
dynamic -> The type is resolved at runtime. Hence compile time checks are not made, and intellisense is not available. It has performance cost also.
In C#, there is no 'var' type. 'var' is just a keyword that tells the compiler to 'analyse whatever comes next to find out the type'. This is done during compilation, not runtime.
The variables you speak of are actually typed as anonymous types that the compiler automatically generates during compilation. Such types, since they have no name, cannot be used to declare parameter types or return values.
You should either create explicit classes for this data, or in .Net4 or later use the Tuple<> generic type.
You could probably use a dynamic reference, but I wouldn't go for that.
Instead, the better option is to create actual classes for those data types and pass them to the methods instead.
For example:
public class MyColumns
{
public string column1 {get;set;}
public string column1 {get;set;}
//etc.
}
Which you can create like this:
var subquery1= from results in table.AsEnumerable()
where //some condition
select new MyColumns
{
column1=results.field1,
column2 = results.field2
//etc.
};
and have a function like this:
public void updategrid(IEnumerable<MyColumns> queries)
{
}
First let me say, that what I want to do is get the value of a property in a generic class that may be overriden by class that inherits from it. Think of it in the base class as a default value, that the inheritor of the class can override to set their own Default value.
I have tried to use reflection directly on the type, using the System.Reflection.FieldInfo.GetValue but this does not work for classes with generic types. So I think that I need to instantiate the class to be able to see what the value is.
The "types" I have I retrieved by reading the Dlls in the bin and using Reflection to find the types that inherit from my interface.
I am using .NET 4.5
here is documentation that seems like it explains exactly what I need to do
http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx
In this documentation the only difference I can see is how we got our types, I looked in the bin for types and they simply called typeof(), Since types are so complex it seems this may be a likely mis-match but I cannot see what is missing(if anything)
foreach (var item in types)
{
var ts = item.GetField("DefaultTimeToExpire");
Type[] typeArguments = item.GetGenericArguments();
if (ts != null)
{
var t = item.MakeGenericType(typeArguments);
var obj = Activator.CreateInstance(t);
var timespan = obj.DefaultTimeToExpire;
subscriberInfos.Add(new Tuple<string, Type, TimeSpan>(item.Name, item, timespan));
}
}
I am calling GetField to look for Items that have a field "DefaultTimeToExpire" so far this part works well to find the type I need.
Next I call GetGenericArguments which returns an expected array of the type Arguments.
then I call MakeGenericType
and finally Create instance wich gives me the error message
"Cannot create an instance of BusinessLogic.TestSubscriberXXX`1[Message] because Type.ContainsGenericParameters is true."
This looks like exactly what I am supposed to do.
Thanks
In order to instantiate a generic type, you need to know the actual values (types) that should be substituted for its type parameters. The GetGenericArguments() method, being a form of reflection, only gives you the type arguments, not their actual values. The values are up to you... that is the entire point of generics.
If item is a type like List<T> then item.GetGenericArguments() will return an array containing a fake "type" representing the type parameter T (with its IsGenericParameter property set to true). Therefore, passing that parameter type back into item.MakeGenericType() will simply create another open generic type equivalent to the original. To close the generic type so that it can be instantiated you need to provide an actual (non-parameter) type argument, such as int.
For example, typeof(List<>).MakeGenericType(typeof(int)) will return typeof(List<int>), while typeof(List<>).MakeGenericType(typeof(List<>).GetGenericArguments()) will simply return typeof(List<>) again. This is what is happening in your code.
I'm sorry if that is a bit opaque, I don't know how else to explain it. The bottom line is that a type like List<T> is only useful if you have a type you want to substitute in place of T.
I have a class that contains a variable of indeterminate type, which must be overridden at runtime, how can I do this?
Sorry for the disgusting question(
Example:
public class MyClass
{
public e_Type TypeValue;
public (variable of indeterminate type) Value;
}
public enum e_Type
{
string, int, bool, byte
}
At runtime variable TypeValue should determine the type of variable Value
Depending on what you actually mean, you should use either var or dynamic.
The var keyword simply lets the compiler take care of deciding which type you are actually using. If the data you will be assigning is truly dynamic during runtime, it won't do you much good. You should mostly look at var as syntactic sugar (even if it at times can be very, very helpful sugar) - i.e. it just saves you typing.
The dynamic keyword lets you create an object that is truly dynamic, that is you will not get a compiler or runtime error no matter what you try to assign to it. The runtime errors will happen later down the road when you try to call on a property that doesn't exist on it. This is essentially you telling the compiler "Hey, look, just don't give me any fuss about this object, allow me to assign anything to it and call anything on it. If I mess up, it's my problem, not yours."
I think whenever you are thinking about using dynamic you should consider the problem at hand and see if it can be solved in a better way (interfaces, generics etc).
It sounds like you're really after generics:
class Foo<T>
{
public T Value { get; set; };
}
Then you can create instances for different types:
Foo<string> x = new Foo<string>();
x.Value = "fred";
Foo<int> y = new Foo<int>();
y.Value = 10;
This is still fixing the type at compile-time - but when the code using the type is compiled.
var is completely wrong here - var is just used for implicitly typed local variables. In particular, you can't apply it to fields.
It's possible that you want dynamic, but it's not really clear from your question at the moment.
I know that this must be done using the keyword var
Nope, that isn't what var does. There are 3 things that leap to mind that would work:
object; can store anything, but requires reflection to do anything useful
dynamic; a special-case of object, where the compiler performs voodoo such that obj.SomeMethod() (etc) is resolved at runtime
generics, i.e. have the class be SomeType<T>, with the variable typed as T; generic constraints can make this T more usable by declaring features (interfaces) that it must have
var has the purpose of referencing anything, not to declare anything. It's the other way around.
I acomplished this once leveraging the System.Dynamic.ExpandoObject (C# 4 only!), it allows for properties to be added at will without declaring them, and they will be resolved at runtime (it resembles how PHP treats objects and I'm a huge fan of it).
A quick example:
dynamic myObject = new ExpandoObject();
myObject.myProperty = "You can declare properties on-the-fly inside me !";
Console.WriteLine(myObject.myProperty);
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());
A junior co-worker of mine managed to write very scary, scary code.
printJob.Type = item[LocalFunctions.GetName(new { printJob.Type })].ToString();
public static string GetName<T>(T item) where T : class
{
try
{
return typeof(T).GetProperties()[0].Name;
}
catch (Exception ex)
{
return null;
}
}
What is you gues what will GetName will output? It will output "Type"!
I just don't get how this is possible. My first thought is that MS will create an anonymous type with property that has the same name as the property from which the value came from (compiler magic?). As this cannot possibly be a supported feature, I advised my junior co-worker to not use things he cannot understand.
But that leaves the question open: How is this possible?
Anonymous types infer property names unless they are specified:
If you do not specify member names in the anonymous type, the compiler
gives the anonymous type members the same name as the property being
used to initialize them.
http://msdn.microsoft.com/en-us/library/bb397696.aspx
The compiler then infers the type for the generic at compile time - so typeof(T) works. It is fully supported, even if the code is fragile. What happens when someone refactors the name of the property?
I'd also say it's inadvisable to advise people on topics you don't have an answer to yourself - this is the source of many a www.thedailywtf.com article ;-)
Personally I'd still remove this in favour of more robust code, instead of assuming the property name is always going to be the same.
That's what the compiler (not MS) does when creating anonymous types. It uses The type, name and order of the supplied parameters to construct a new type. This is fully supported and intended to be that way, so there's no reason not to use it.
The compiler has all the information available to do this. It sees what name and type the properties you used to initialize it have (such as printJob.Type) and can use that information to generate the anonymous type for you.
See here for more information:
http://msdn.microsoft.com/en-us/library/bb397696.aspx