Default value and linq - c#

Why this simple code doesnt work?
var abc = new[]{1,2,3,4}.Select(x => default(typeof(x)));
i expect something like array of zeros but get compiler error. So how i can default values in lambda expressions?
In my real application i have meta class with type Type
public class FieldInfo
{
public Type type
}
I get IEnumerable<FieldInfo> as parameter to my method and want return an array of default values for each type (object[])

This is the problem:
typeof(x)
You're using the typeof operator as if it's a method call, taking a value. It's not. It needs a compile-time type name or type parameter (or unbound type such as Dictionary<,>, or void).
The same is try with the default operator.
So that's what's wrong - but without knowing what you're trying to achieve, we can't actually advise you on how to fix it. You might just want something like this:
public static IEnumerable<T> SelectDefault<T>(this IEnumerable<T> source)
{
return source.Select(x => default(T));
}
Then this:
var abc = new[]{1,2,3,4}.SelectDefault().ToArray();
... would give you an int[] with all values zero.
EDIT: Now we have more information, it's easier to provide what you want, which is basically a method to get the default value from a Type, boxing as appropriate:
public static object GetDefaultValue(Type type)
{
// Non-nullable value types should be boxed, basically
if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
{
// Not the swiftest approach in the world, but it works...
return Activator.CreateInstance(type);
}
// Everything else defaults to null
return null;
}
So you'd have something like:
var defaults = fields.Select(field => GetDefaultValue(field.type));
(Where field is a FieldInfo as per the question - I'm deliberately not calling GetType() here.)

Do you mean this?
var abc = new[]
{
1, 2, 3, 4
}
.Select(x = > {
var xType = x.GetType();
if (xType.IsValueType)
{
return Activator.CreateInstance(xType);
}
else
{
return null;
}
})

You can't get the default value at runtime this way, default() and typeof() are compile time features. But you can try this suggestion. It uses Activator.CreateInstance to get the default value for a value type at runtime.

The compiler needs a compile-time type:
var abc = new[]{1,2,3,4}.Select(x => default(Int32));
will generate all 0's. I have no idea what you are trying to achieve with this, though, because all this does is return an empty array with the default value.

Related

Casting an object into the same type as an IEnumerable collection

In essence I have function which takes arguments : ContainsValue(IEnumerable collection, object obj)
And I need to check if collection Contains obj with the use of Equals().
Specifically collection is an array of strings and obj is a custom type/class (Its called FString, I dont completely understand what it is but it is at least somewhat derivative from string).
Unfortunately the solution needs to be generic so I cant explicitly reference the custom type.
And so I need a way to generically cast obj into whatever type the collection is.
Is this possible?
EDIT:
static bool ContainsValue(IEnumerable collection, object obj)
{
// cast obj into same type as collection elements
foreach(var element in collection)
{
if() // element equals obj
{
return true;
}
}
return false;
}
You should just be able to use this in your if statement:
if(object.Equals(element, obj))
and then you don't need to cast at all, or worry about nulls, etc.
The details are quite vague but Enumerable.Cast(IEnumerable) Method may help.
Doco, with an example, here.
System.Collections.ArrayList fruits = new System.Collections.ArrayList();
fruits.Add("mango");
fruits.Add("apple");
fruits.Add("lemon");
IEnumerable<string> query =
fruits.Cast<string>().OrderBy(fruit => fruit).Select(fruit => fruit);
// The following code, without the cast, doesn't compile.
//IEnumerable<string> query1 =
// fruits.OrderBy(fruit => fruit).Select(fruit => fruit);
foreach (string fruit in query)
{
Console.WriteLine(fruit);
}
// This code produces the following output:
//
// apple
// lemon
// mango
You can use it like this (if you can access fields of the collection):
string objAsString = obj?.ToString() ?? "";
if(collection.Any(x => x.field == objAsString))
{
//Do something...
}
Use IEnumerable's OfType method to extract the target type you are looking for and if there are some check the equality situation you mentioned...such as this example
return collection.OfType<string>()
.Any( str => str.Equals("Jabberwocky"));
And so I need a way to generically cast obj into whatever type the collection is. Is this possible?
If that is your only question then the solution is easy. Please edit your question if you need something more than this.
static bool ContainsValue<T>(IEnumerable<T> collection, object obj) where T : class
{
var compareTo = obj as T;
if (obj == null) return false; //Return false if cast was not possible
foreach (var item in collection)
{
if (item == obj) return true;
}
return false;
}
You could also force the caller to do the cast, which seems like a smarter way to go about it, since then you can enforce type safety at compile time. Also you can shorten the code with a tiny bit of LINQ.
static bool ContainsValue<T>(IEnumerable<T> collection, T obj) where T : class
{
return collection.Any( item => item == obj );
}

How to use variable type in as operator

For example:I have 2 variable (value ) & (property) i want to check is cast possible for value? We do not know the type of variables, How to check if cast is possible?
var value = Reader[item];
PropertyInfo property = properties.Where(x => x.Name == item).FirstOrDefault();
var type=property.PropertyType;//Or property.ReflectedType
var cs= value as type // Error: type is variable but is used like a Type
if (cs!=null){
...
}
Sample 1:
var value = 123;//is int
type = property.GetType();// is double
var x = (double)value;//Can be casted
Sample 2:
var value = "asd";//is string
type = property.GetType();// is double
var x = (double)value;//Can not be casted
You can use IsAssignable:
bool isValidCast = type.IsAssignableFrom(value.GetType())
As per the comments about int to double:
I've made a mistake in my comment, so i deleted it.
int can be implicitly converted to double because there is a predefined implicit conversion, see here
There are many ways to convert or cast from type to type. For example, You can use implicit/explicit conversion, you can use TypeConverter or implement the IConvertible interface.
Now, you have to decide which use case is relevant to you. It can be a bit complex to check them all, especially without knowing the destination type at design time.
In your code snippet, type is a variable of type Type, hence why it is throwing that error. You can change your code to use Convert.ChangeType() instead. Something like this:
var value = Reader[item];
PropertyInfo property = properties.Where(x => x.Name == item).FirstOrDefault();
var type=property.PropertyType;
object cs= Convert.ChangeType(value, type);
if (cs!=null){
...
}
Notice that, since you don't know the strong type of your property at compile time, you still have to box it into an object type after changing its type. This means you wouldn't be able to access its properties and methods directly using dot syntax in code (e.g. cs.MyProperty). If you wish to be able to do that, you can use the dynamic type in C#:
dynamic dcs = cs;
Console.Write(dcs.MyProperty);
When using Convert.ChangeType() you have to make sure you are converting to the correct type. E.g.:
if (value.GetType() == type)
{
object cs= Convert.ChangeType(value, type);
}

Dapper: What's the difference between these two pieces of code?

I've registered a custom type handler for Dapper to Json serialize a string. This works as expected. However, whilst coding, I discovered two pieces of code after refactoring, the latter one which didn't trigger the datatype handler, but should in my opinion, so what's the difference?
First the code that works as expected - the custom type handler is called by dapper, and the data is serialized when inserted into the table:
if (val.GetType() != typeof (String))
{
var v = new JsonString {Value = val};
this.Connection.Execute("insert into misc (k,v) values (#keyName, #v)",
new { keyName, v });
}
else
{
this.Connection.Execute("insert into misc (k,v) values (#keyName, #val)",
new { keyName, val });
}
Now for the code which doesn't work as it inserts into the table the fully qualified type string instead of the serialized data, but which I think is semantically similar:
var v = val.GetType() != typeof (String)
? new JsonString {Value = val}
: val;
// t is set to type of JsonString, therefore the dapper type handler should be used
var t = v.GetType();
this.Connection.Execute("insert into misc (k,v) values (#keyName, #v)",
new { keyName, v });
Is it a dapper bug or a c# oddity? I assume it's something to do with the auto typing in the ternary conditional which is the failing point, but t is set to the data type that is serialized by Dapper (or rather the custom type handler). What's the difference?
I am going to assume that the compile-time type (i.e. declaration type) of val is System.Object. I will explain why the two situations are not equivalent.
One must be careful to distinguish between the compile-time type of a variable and the actual run-time type (which is found by .GetType()).
In the first piece of code, in the branch where val is not String at run-time, we declare:
var v = new JsonString {Value = val};
Here var is substituted by JsonString since that is the compile-time type of the right-hand side of the = assignment. Then the anonymous type instance:
new { keyName, v }
is going to be a class (I will call it class Anonymous1) with a member
public JsonString v { get { ... } }
Now, in the second piece of code, we have instead:
var v = val.GetType() != typeof (String)
? new JsonString {Value = val}
: val;
The compile-time types of the operands to the ternary operator are:
{bool} ? {JsonString} : {object}
At compile-time, a best common type for JsonString and object must be found. That common type is object. So object becomes the compile-time type of v here, i.e. var means object here.
Then the anonymous type:
new { keyName, v }
is a type "Anonumous2" whose "2nd" property reads:
public object v { get { ... } }
So to sum up: In the first case you pass in an object which has a property v declared as a JsonString which when retrieved returns a JsonSting that happens to have run-time JsonString. In the second code sample you pass in an object which has a property v declared as object which when retrieved returns an object that happens to have run-time type JsonString.
I do not know much on how Dapper works! But presumably when it sees (by reflection?) that the property type is object, it simply calls .ToString() on it. If that object happens to be of run-time type string, that should be OK, since string.ToString() is overridden. But JsonString.ToString() is not like that.
When Dapper sees the property is declared as JsonString, Dapper does something smarter than calling .ToString().
Assuming there is no implicit conversion available between JsonString and String, the code in the second example won't work. If there is an implicit conversion available, you need to provide more information about the exception that is occurring.
WIth no conversion available between JsonString, a variable declared with type var has a type that is inferred by the compiler ((https://msdn.microsoft.com/en-us/library/bb384061.aspx). In this case, variable v is either of type JsonString or String depending upon which part of the assignment occurs. If the compiler assumes it is of type JsonString, any assignment with a String will fail.
In your second code example, the first line of code is wrong since the assignment results in two different data types getting assign to variable v.

Reflection and how to handle enums

I want to use something similar as:
object ob;
var props = ob.GetType().GetProperties();
List<Element> list = new List<Element>();
foreach (var prop in props)
{
if (prop.PropertyType == typeof(String))
list.Add(makeStringProperty(prop));
else if (prop.PropertyType == typeof(int))
list.Add(makeIntProperty(prop));
else
{
}
}
which adds something to the given list for every property in a given object. Now I want to add a clause for also adding enum-variables, including getting all its values by Enum.GetValues() f.e..
That would be easy for any one given enum, but I want this to be generic for every possible enum,
so for example if ob would have:
enum Weather {
sunny,
rainy,
cloudy
}
Weather weather = sunny;
enum Places {
beach,
mall,
home
}
Places place = beach;
I would be able to get both variables themselves AND all the values of both Enums.
Of course I can't directly check typeof(Enum) or anything.
Does someone have a clue?
else if(prop.PropertyType.IsEnum)
{
var values = Enum.GetValues(prop.PropertyType);
}
It's something like
typeof(Weather).GetFields()
or
ob.GetType().GetFields()
if you want to use reflection directly on an enum type. The members of an enum are a kind of static fields.
But you can also use
Enum.GetValues(ob.GetType())
In any case, if there's doubt, you should check if it is an enum or not first:
var typeOfOb = ob.GetType();
if (typeOfOb.IsEnum)
{
// use Enum.GetValues(typeOfOb) here
}
Note: System.Type is the class used for both a type determined compile-time, like typeof(Weather), and a type determined run-time, like ob.GetType(). So you can use both as an argument to the GetValues(System.Type) static method.

Any way to get the type of Tuple<> item(s)

where the def is
IEnumerable<Tuple<string, double>> GetValues()
{
....
yield return new Tuple<string,double>(dataRow["<field>"].ToString(),
(double)Convert.ChangeType(dataRow["<field>"], typeof(double)));
....
// and more code similar to above based on other custom logic
}
as you can see, that,s a lot of casting/coerc'ng to double
it may still change back to string or to other datatypes
wondering if there is a way to get the datatypes of Tuple defined in the signature so i can create some generic helper and not worry about missing some conversion somewhere
It should be possible with Reflection? i hope !
If this is the DataRow class, you have a nice extension method called Field for this.
IEnumerable<Tuple<T1, T2>> GetValues<T1, T2>(String field1, String field2)
{
....
yield return new Tuple<T1,T2>(dataRow.Field<T1>("<field>"),
dataRow.Field<T2>("<field>"));
....
}
If you have an instance of the Tuple you can get the generic type parameters via reflection:
var x = Tuple.Create<int, string>(0, "test");
var y = x.GetType().GetGenericArguments();
y[0].Name = "System.Int32";
You can get this same information at compile-time using "typeof()", or at runtime using reflection, like so:
public Tuple<string, double> DoSomething()
{
var y = typeof(Tuple<string, double>).GetGenericArguments();
var z = MethodBase.GetCurrentMethod().ReturnType.GetGenericArguments();
}
I don't think this is really going to help you; you can't bind the type information obtained at run-time to generic parameters at compile type, so you aren't saving yourself a whole lot of work. You will still end up having to specify the data types repeatedly somewhere.
Chris Shain's answer (the Field<T> method) really is the way to go here.
Not sure, but could the following be of help?
bool bStringResult = false, bDoubleResult = false;
string sString = string.Empty;
double dDouble = 0;
Tuple<string, double> tTuple = Tuple.Create(sString, dDouble);
if (tTuple.Item1.GetType() == typeof(string)) bStringResult = true;
if (tTuple.Item2.GetType() == typeof(double)) bDoubleResult = true;
Console.WriteLine($"String: {bStringResult}, Double: {bDoubleResult}");
Result : String: True, Double: True

Categories

Resources