I have a large number of classes.
From this list I get a specified type
Type aType = Type.GetType(...);
Now I want to use this type in a linq statement like:
var aResult = from obj in scope.Extent<aType>() select obj;
This does not seem to be possible, as Extent does not accept Type.
Is there any way now (with .net 4.5) to call the statement?
All I want to do is to say use Type as class. Don't invoke the class, only get with linq all objects of this type from a scope.
You can't use an instance of Type as a generic type argument - not at compile time, anyway.
If you want objects of a specific type, you could do
var aResult = from obj in scope where obj.GetType() == aType select obj;
Note that this requires an exact type match, rather than any kind of "can be assigned to" relationship.
Also note that this will only get you a series of objects - again there's no compile-time way to cast things to an instance of Type.
Related
I have C# ArrayList and added two items int and string type
Now in for loop Item returns and captured in var type at run time.
How this var type decide data type at compile time????
ArrayList al = new ArrayList();
al.Add(10);
al.Add("A");
for(int i=0; i<2;i++)
{
var val = al[i];
Console.WriteLine("type of value is {0} and {1}",val.GetType(),val);
}
var is used for type inference at compile time. The compiler determines the variable type given all the information it has about the expression al[i] at that time.
Since the indexer property of ArrayList is of type object, the compiler infers the type of val to be object.
At runtime, when calling val.GetType() you have access to the actual type of val: either int or string in your case. But the type of the val variable is still object.
The same mechanism happens if you write:
object o = new int();
Console.WriteLine(o.GetType());
You'd see "System.Int32" although the type of o is object.
Link to fiddle
var is purely compiler "magic", nothing special happens at runtime.
It's your way of saying "compiler, you figure out the correct data type for this variable declaration. I either don't want to, am not too concerned about the specific type, or it's got an unpronounceable name1"
So, the compiler first works out the data type of the expression that's being used to initialize the variable, and gives the variable that type.
Here, the expression's simple - you're accessing the Item property of ArrayList via C#'s indexer syntax. That property returns object, so that's the type of the val variable.
All of that happens at compile time.
1When LINQ was introduced, anonymous types arrived in the language. These are real types generated by the compiler, but they're deliberately given names that, whilst valid names so far as the CLR is concerned, aren't valid names so far as C# is concerned. You don't know their names and even if you did, you wouldn't write them in C#.
It's why var had to be added to the language, the other reasons are convenient outcomes of that decision.
As other said here ArrayList implementation is based on object. Var only infers the type of the right side of the assignment, which in this case is a type of an object, feel free to use in this case object. You should not get any exception. Because ArrayList has not a generic implementation you need to unbox the items to a specific type if you want to treat them differently.
Basically you have a similar effect using a generic list of object.
Here is the implementation of the class, so you can see by yourself the internal implementation
https://referencesource.microsoft.com/#mscorlib/system/collections/arraylist.cs
Hope this helps
This code results in an error: type or namespace "index" could not be found.
foreach (var index in Model.UserAssets.Keys)
{
foreach (var asset in Model.UserAssets[index])
{
var val = asset as index.getType();
}
}
Why doesn't this work? Is it because index is not in scope (although it should be)?
The variable index is in scope, but as only allows a Type: expr as T.
So in asset as index.getType(), the compiler is attempting to treat index like a type, which it is not, and never even considers that there is a variable with the given name.
Trying to cast (including using as) on run-time type information, such as included in a Type instance, generally doesn't make sense. For why, and alternatives, consider
Typecasting base class reference to its actual type
How to cast object to type described by Type class?
How to cast an object value to Type values?
Cast a variable to a Type and call Methods
As stated before, the variable index is in scope, but you're trying to treat the Type object as a Type. This isn't quite the case - GetType() returns an object of the Type class, used for reflection. An object of thus can also be return using the typeof() statement.
Both is and as are keyword which support direct Type checking, which works differently and must be a direct class reference. If you wish, however, you could compile a lambda representing the above statement using Expressions, wherein it will dynamically build your statement at runtime.
using System.Linq.Expressions;
...
if(index.GetType().IsAssignableFrom(asset.GetType())) return; // This will prevent an InvlaidCatException
var param = Expression.Parameter(asset.GetType());
var exp = Expression
.Convert(
param,
index.GetType());
var del = Expression.Lambda(exp, param).Compile();
var val = del.DynamicInvoke(index);
So I have class which accepts a generic type parameter and does a little special handling if the type parameter is a subclass of a given type.
IEnumerable<T> models = ...
// Special handling of MySpecialModel
if (filterString != null && typeof(MySpecialModel).IsAssignableFrom(typeof(T)))
{
var filters = filterString.Split(...);
models =
from m in models.Cast<MySpecialModel>()
where (from t in m.Tags
from f in filters
where t.IndexOf(f, StringComparison.CurrentCultureIgnoreCase) >= 0
select t)
.Any()
select (T)m;
}
But I'm getting an exception on the last line
Cannot convert type 'MySpecialModel' to 'T'
If I change the code to use as instead of casting, I get this error.
The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint.
What am I missing here?
Update
This class needs can take any type parameter, including structs and built-in types, so a generic constraint would not be a suitable solution in my case.
Do Select(x => (MySpecialModel)x)
The LINQ Cast<T> method will only work for casting elements to that the element already is (such as a base type, derived type, or interface). It is not intended to cast objects that are able to be cast to a target type. (e.g. new List<int>{1,2,3}.Cast<long>() will throw an exception as well.
The above answer wasn't wrong, but it doesn't address the question.
Just because you have proved with reflection that a generic parameter is bound to a given type, doesn't mean that the compiler knows that it is. In order to make this work, you will need to cast your T instance to a common type (e.g. object), then cast it to the specific type. e.g. (changing the last line in your query to select (T)(object)m should do the trick.
Try the following
select (T)(object)m;
At runtime you've verified that T is a subtype of MySpecialModel but the compiler doesn't have access to this information at compile time. It just sees an attempted conversion between 2 unrelated types: T and MySpecialModel.
To work around this you need to use object as a middle man. The compiler understands how to convert MySpecialModel to object and to go from object to T.
The most straightforward fix is to cast to object first before the cast to T:
select (T)(object)m;
The problem is your check occurs at runtime, but the compiler doesn't know that T must be an instance of MySpecialModel within the if statement. Therefore it just sees you are trying to cast to some arbitrary type T from MySpecialModel which is not safe, hence the error.
If you know that the generic type will always be a class, you can add a type constraint on your class:
public class Test<T> where T : class {}
Otherwise perform a double cast via object as smartcaveman has suggested:
.Select(x => (T)(object)x);
To use the as keyword, put the class constraint on your generic parameter:
void MyMethod<T>(T item) where T : class
{
//...
}
You might apply Nullable<T> constraint - that should enable the possibility to cast (at least using "as").
Why do the two last lines not work and give me
The type or namespace name 'myType' could not be found
Type myType = this.GetType();
bool test = obj is myType;
var p = (myType)obj;
You need to do:
bool test = myType.IsInstanceOfType(obj);
or
bool test = myType.IsAssignableFrom(obj.GetType());
// var p = Convert.ChangeType(obj, myType); - update: this is not what the OP asked
For the second one, you can't "cast" an expression to a type which is not known at compile time. The point of casting is to reference the members of that type natively. If you don't know what the type is at compile type (because you are using .GetType()), then there is no point casting, and indeed it's impossible.
C# is a statically typed language, which means types must be known at compile time. The var keyword just means "Figure out what this type should be automatically (through inference) at compile time".
Any cast or type-check has to be against a static type. You are actually trying to use an instance of an object of type Type that describes a type. That instance is provided to you by .NET Reflection.
Once you are working with an object of a type derived at runtime you have to use reflection for all operations on that instance. For example, you can do something like this:
bool test = myType.IsInstanceOfType(obj);
bool test = typeof(obj).IsAssignableFrom(myType); // Good for checking if a type implements an interface
For your second line, you can use an object reference to hold any type:
object p = obj;
The type of object being cast to must be determined at compile time in C#. You're trying to make a cast based on the runtime type of the object which is incompatible with this notion. Hence you get this error.
Can you give us an example of what you want to do with p? There is likely a cleaner way.
If you want to know if an object is an instance or implementation of a Type at runtime, you need to do:
Type thisType = this.GetType();
Type objType = obj.GetType();
if(objType.IsAssignableFrom(type))
{
// do your stuff
}
From there, there is no way to cast an object to a runtime type since the compiler need that information at compile time. However, if you are using C# 4, you can use the dynamic type.
Type thisType = this.GetType();
Type objType = obj.GetType();
if(objType.IsAssignableFrom(type))
{
dynamic dynObj = obj;
dynObj.CallWhateverIWant();
}
However, looking at your code, there is obviously a better way to do want you want to do. Maybe you could implement some kind of interface, common to both classes and use functions from that interface at compile time.
I don't have a Visual Studio ready at the moment and this isn't something I need to do often, but for the second line I think it should look like this:
bool test = obj is typeof(this);
The third line is not possible unless you have a limited set of possible types you can switch on.
the is operator works on classes, not objects of type Type
If you want to do this sort of thing, use the dynamic keyword
http://msdn.microsoft.com/en-us/library/dd264736.aspx
I have a Dictionary(TKey, TValue) like
Dictionary<int, ArrayList> Deduction_Employees =
new Dictionary<int, ArrayList>();
and later I add to that array list an anonymous type like this
var day_and_type = new {
TheDay = myDay,
EntranceOrExit = isEntranceDelay
};
Deduction_Employees[Employee_ID].Add(day_and_type);
Now how can I unbox that var and access those properties ??
First, you aren't unboxing the type. Anonymous types are reference types, not structures.
Even though you can technically create instances of the same type outside of the method they were declared in (as per section 7.5.10.6 of the C# 3.0 Language Specification, which states:
Within the same program, two anonymous
object initializers that specify a
sequence of properties of the same
names and compile-time types in the
same order will produce instances of
the same anonymous type.
) you have no way of getting the name of the type, which you need in order to perform the cast from Object back to the type you created. You would have to resort to a cast-by-example solution which is inherently flawed.
Cast-by-example is flawed because from a design standpoint, every single place you want to access the type outside the function it is declared (and still inside the same module), you have to effectively declare the type all over again.
It's a duplication of effort that leads to sloppy design and implementation.
If you are using .NET 4.0, then you could place the object instance in a dynamic variable. However, the major drawback is the lack of compile-time verification of member access. You could easily misspell the name of the member, and then you have a run-time error instead of a compile-time error.
Ultimately, if you find the need to use an anonymous type outside the method it is declared in, then the only good solution is to create a concrete type and substitute the anonymous type for the concrete type.
There are several ways.
Since the comments seems to indicate that I suggest you do this, let me make it clear: You should be creating a named type for your object since you intend to pass it around.
First, you can use Reflection, which another answer here has already pointed out.
Another way, which tricks .NET into giving you the right type is known as "cast by example", and it goes something like this: You need to pass your object through a generic method call, which will return the object as the right type, by inferring the right type to return.
For instance, try this:
private static T CastByExample<T>(T example, object value)
{
return (T)value;
}
and to use it:
var x = CastByExample(new { TheDay = ??, EntranceOrExit = ?? }, obj);
for the two ?? spots, you just need to pass something fitting the data type for those properties, the values will not be used.
This exploits the fact that multiple anonymous types containing the exact same properties, of the same type, in the same order, in the same assembly, will map to the same single type.
However, by this time you should be creating a named type instead.
An anonymous type has method scope. To pass an anonymous type, or a collection that contains anonymous types, outside a method boundary, you must first cast the type to object. However, this defeats the strong typing of the anonymous type. If you must store your query results or pass them outside the method boundary, consider using an ordinary named struct or class instead of an anonymous type.
Source: http://msdn.microsoft.com/en-us/library/bb397696.aspx
No you can't. You can only access the properties by using reflection. The compiler has no way of knowing what the type was, and since it's an anonymous type, you can't cast it either.
If you are using .NET 1.x - 3.x, you must use reflection.
If you use .NET 4.0, you could use a dynamic type and call the expected properties.
In neither case do you need to unbox; that's for value types. Anonymous types are always reference types.