What does this mean??
var cdParams = (includeUniversals)
? new[] {pageDictionary[pageName], pageDictionary[CNNService.UniversalPage.Name]}
: new[] {pageDictionary[pageName]};
Basically it boils down to what does ? mean and what does new[] mean?
It's roughly equivalent to this:
Foo[] cdParams; // Use the correct type instead of Foo. NB: var won't work here.
if (includeUniversals) {
dParams = new Foo[2];
dParams[0] = pageDictionary[pageName];
dParams[1] = pageDictionary[CNNService.UniversalPage.Name];
} else {
dParams = new Foo[1];
dParams[0] = pageDictionary[pageName];
}
It's a ternary expression. If the condition is true, then execute the first case. If it is false, then execute the second case.
If the boolean includeUniversals evaluates to true then return a new anonymous object array containing pageDictionary[pageName] and pageDictionary[CNNService.UniversalPage.Name] otherwise return a new anonymous object array containing pageDictionary[pageName]
That what you are looking for?
var cdParams // type inferred by the compiler
= (includeUniversals) ? // if includeUniversals is true
// then cdParams = new a new array with 2 values coming from a dictionary
new[] { pageDictionary[pageName], pageDictionary[CNNService.UniversalPage.Name] }
// otherwise, cdParams = a new array with one value
: new[] { pageDictionary[pageName] };
See ternary operator and implicit array typing.
Depending on includeUniversals, cdParams will be an array with two values in it, namely pageDictionary[pageName] and pageDictionary[CNNService.UniversalPage.Name] - OR, it will be an array with one value in it, namely pageDictionary[pageName].
Related
So this code compiles:
var foo = new[]
{
new { prop1 = 1, prop2 = "whatever" },
default,
new { prop1 = 2, prop2 = "something" },
};
But the following doesn't:
var foo = new[]
{
new { value = new { prop1 = 1, prop2 = "whatever" } },
new { value = default },
new { value = new { prop1 = 2, prop2 = "something" } },
};
And so far the only way I can find to get it to do so is via:
T MakeDefaultOf<T>(T dummy) => default(T);
var foo = new[]
{
new { value = new { prop1 = 1, prop2 = "whatever" } },
new { value = MakeDefaultOf(new { prop1 = 0, prop2 = "" }) },
new { value = new { prop1 = 2, prop2 = "something" } }
};
But it would seem for both the first two examples the compiler has enough information to work out the implicit type of 'default' - so is there a reason it doesn't? Are there any ways of achieving what I want without an ancillary function or variable?
Depending on your use case, you may get away with this:
var foo = new[]
{
new { prop1 = 1, prop2 = "whatever" },
default,
new { prop1 = 2, prop2 = "something" },
}.Select(x => new { value = x } ).ToArray();
I'm not aware of any syntax sugar to initialize such default values.
The reason why second (new {value = default} ) initialization fails is due to
C# arrays
For a single-dimensional array, the array initializer must consist of a sequence of expressions that are assignment compatible with the element type of the array.
Compiler checks type of each individual element and then computes the best suitable base type. There is no second pass over objects to figure out if all can be made compatible with the likely resulting type (which had to be the first step to implement the behavior you expect).
As result the compiler tries to reason what new {value = default} is and there is not enough information to construct the type. Note that passing null instead default would not help as it will not define particular type - the helper method you have need to be used to provide the exact type for null at this point. And the resulting type must be exactly the same as all other elements of array because anonymous types must match exactly to be assignment compatible - C# anonymous types:
Anonymous types are class types that derive directly from object, and that cannot be cast to any type except object...
...If two or more anonymous object initializers in an assembly specify a sequence of properties that are in the same order and that have the same names and types, the compiler treats the objects as instances of the same type.
But it would seem for both the first two examples the compiler has
enough information to work out the implicit type of 'default' - so is
there a reason it doesn't?
The problem is not related to the array per se. It's the fact that the compiler simply doesn't allow you to initialize an anonymous type with a null/default value according to Compiler Error CS0828:
An anonymous type cannot be initialized with a null value or an unsafe
type, or a method group or anonymous function.
Let's forget about the array for a moment and consider the following code:
var bar = new { value = default }; // Or new { value = null }
Now, the compiler has no way of knowing the type of value and, therefore, can't infer the type of bar.
That is the cause of the problem at hand. All you did is that you added bar to an array of anonymous types. Yes, the compiler should be able to infer the type of the array element based on the other elements but now bar, as an element of the array, has a type that the compiler doesn't recognize, it wasn't able to make sure all the elements of the array are of the same type (because it's an implicitly typed array).
I am attempting to implement a method like:
(Func<T> getFn, Action<T> setFn) MakePair<T>(T initialVal) {
}
It will return two runtime generated lambdas that get and set a dynamically created variable using Expression trees to create the code.
My current solution is to dynamically create an array of the type with one element, and reference that:
(Func<T> getFn, Action<T> setFn) MakePair<T>(T initialVal) {
var dynvar = Array.CreateInstance(typeof(T), 1);
Expression<Func<Array>> f = () => dynvar;
var dynref = Expression.Convert(f.Body, typeof(T).MakeArrayType());
var e0 = Expression.Constant(0);
var getBody = Expression.ArrayIndex(dynref, e0);
var setParam = Expression.Parameter(typeof(T));
var setBody = Expression.Assign(Expression.ArrayAccess(dynref, e0), setParam);
var getFn = Expression.Lambda<Func<T>>(getBody).Compile();
var setFn = Expression.Lambda<Action<T>>(setBody, setParam).Compile();
return (getFn, setFn);
}
Is there a better way to create what may be a value type variable at runtime that can be read/written to than using an array?
Is there a better way to reference the runtime created array other than using a lambda to create the (field?) reference for use in the ArrayIndex/ArrayAccess method calls?
Excessive Background Info
For those that wonder, ultimately this came up in an attempt to create something like Perl auto-virification of lvalues for Perl hashes.
Imagine you have a List<T> with duplicate elements and want to create a Dictionary<T,int> that allows you to look up the count for each unique T in the list. You can use a few lines of code to count (in this case T is int):
var countDict = new Dictionary<int, int>();
foreach (var n in testarray) {
countDict.TryGetValue(n, out int c);
countDict[n] = c + 1;
}
But I want to do this with LINQ, and I want to avoid double-indexing countDict (interestingly, ConcurrentDictionary has AddOrUpdate for this purpose) so I use Aggregate:
var countDict = testarray.Aggregate(new Dictionary<int,int>(), (d, n) => { ++d[n]; return d; });
But this has a couple of issues. First, Dictionary won't create a value for a missing value, so you need a new type of Dictionary that auto-creates missing values using e.g. a seed lambda:
var countDict = testarray.Aggregate(new SeedDictionary<int, Ref<int>>(() => Ref.Of(() => 0)), (d, n) => { var r = d[n]; ++r.Value; return d; });
But you still have the lvalue problem, so you replace the plain int counter with a Ref class. Unfortunately, C# can't create a C++ first class Ref class, but using one based around auto-creating a setter lambda from a getter lambda (using expression trees) is close enough. (Unfortunately C# still won't accept ++d[n].Value; even though it should be valid, so you have to create a temporary.)
But now you have the problem of creating multiple runtime integer variables to hold the counts. I extended the Ref<> class to take a lambda that returns a constant (ConstantExpression) and create a runtime variable and build a getter and setter with the constant being the initial value.
I agree with some of the question commenters that expression trees seem unnecessary, so here is a simple implementation of the shown API without them:
struct Box<T> {
public T Value;
}
(Func<T> getFn, Action<T> setFn) MakePair<T>(T initialVal) {
var box = new Box<T> { Value = initialVal };
return (() => box.Value, v => box.Value = v);
}
As an answer to the stated question (how to define dynref without a lambda), then, is there something wrong with the following modifications to dynvar and dynref?
var dynvar = new T[] { initialVal };
var dynref = Expression.Constant(dynvar);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I get the Array Item Type from Array Type in .net
If I have an array of a particular type is there a way to tell what exactly that type is?
var arr = new []{ "string1", "string2" };
var t = arr.GetType();
t.IsArray //Evaluates to true
//How do I determine it's an array of strings?
t.ArrayType == typeof(string) //obviously doesn't work
Type.GetElementType - When overridden in a derived class, returns the Type of the object encompassed or referred to by the current array, pointer or reference type.
var arr = new []{ "string1", "string2" };
Type type = array.GetType().GetElementType();
As your type is known at compile time, you can just check in a C++ way. Like this:
using System;
public class Test
{
public static void Main()
{
var a = new[] { "s" };
var b = new[] { 1 };
Console.WriteLine(IsStringArray(a));
Console.WriteLine(IsStringArray(b));
}
static bool IsStringArray<T>(T[] t)
{
return typeof(T) == typeof(string);
}
}
(produces True, False)
I have an expression tree function from a previous SO question. It basically allows the conversion of a data row into a specific class.
This code works fine, unless you're dealing with data types that can be bigger or smaller (eg. Int32/Int64).
The code throws an invalid cast exception when going from an Int64 to an Int32 when the value would fit in an Int32 (eg. numbers in the 3000).
Should I?
Attempt to fix this in the code? (If so, any pointers?)
Leave the code as it is.
private Func<SqlDataReader, T> getExpressionDelegate<T>()
{
// hang on to row[string] property
var indexerProperty = typeof(SqlDataReader).GetProperty("Item", new[] { typeof(string) });
// list of statements in our dynamic method
var statements = new List<Expression>();
// store instance for setting of properties
ParameterExpression instanceParameter = Expression.Variable(typeof(T));
ParameterExpression sqlDataReaderParameter = Expression.Parameter(typeof(SqlDataReader));
// create and assign new T to variable: var instance = new T();
BinaryExpression createInstance = Expression.Assign(instanceParameter, Expression.New(typeof(T)));
statements.Add(createInstance);
foreach (var property in typeof(T).GetProperties())
{
// instance.MyProperty
MemberExpression getProperty = Expression.Property(instanceParameter, property);
// row[property] -- NOTE: this assumes column names are the same as PropertyInfo names on T
IndexExpression readValue = Expression.MakeIndex(sqlDataReaderParameter, indexerProperty, new[] { Expression.Constant(property.Name) });
// instance.MyProperty = row[property]
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
statements.Add(assignProperty);
}
var returnStatement = instanceParameter;
statements.Add(returnStatement);
var body = Expression.Block(instanceParameter.Type, new[] { instanceParameter }, statements.ToArray());
var lambda = Expression.Lambda<Func<SqlDataReader, T>>(body, sqlDataReaderParameter);
// cache me!
return lambda.Compile();
}
Update:
I have now given up and decided it is not worth it. From the comments below, I got as far as:
if (readValue.Type != property.PropertyType)
{
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(Expression.Call(property.PropertyType, "Parse", null, new Expression[] { Expression.ConvertChecked(readValue, typeof(string)) }), property.PropertyType));
statements.Add(assignProperty);
}
else
{
// instance.MyProperty = row[property]
BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
statements.Add(assignProperty);
}
I don't think I was too far off, feel free to finish it and post the answer if you figure it out :)
You could try to fix it by "convert checked" before assigning i.e. using Expression.ConvertChecked on the value instead of Expression.Convert .
Couldn't try it right now but this should take care of the case you describe...
EDIT - as per comment this could be a boxing issue:
In this case you could try using Expression.TypeAs or Expression.Unbox for the conversion or use Expression.Call for calling a method to do the conversion... an example for using Call can be found at http://msdn.microsoft.com/en-us/library/bb349020.aspx
What you're trying to build is actually much more complicated if you want to support 100% of the primitives in .NET and SQL.
If you don't care about some of the edge cases (nullable types, enums, byte arrays, etc), two tips to get you 90% there:
Don't use the indexer on IDataRecord, it returns an object and the boxing/unboxing will kill performance. Instead, notice that IDataRecord has Get[typeName] methods on it. These exist for all .NET primitive types (note: it's GetFloat, not GetSingle, huge annoyance).
You can use IDataRecord.GetFieldType to figure out which Get method you need to call for a given column. Once you have that, you can use Expression.Convert to coerce the DB column type to the target property's type (if they're different). This will fail for some of the edge cases I listed above, for those you need custom logic.
Bit of a strange one this. Please forgive the semi-pseudo code below. I have a list of enumerated values. Let's say for instance, like so:
public enum Types
{
foo = 1,
bar = 2,
baz = 3
}
Which would become, respectfully, in the code:
Types.foo
Types.bar
Types.baz
Now I have a drop down list that contains the following List Items:
var li1 = new ListItem() { Key = "foo" Value = "Actual Representation of Foo" }
var li2 = new ListItem() { Key = "bar" Value = "Actual Representation of Bar" }
var li3 = new ListItem() { Key = "baz" Value = "Actual Representation of Baz" }
for the sake of completeness:
dropDownListId.Items.Add(li1); dropDownListId.Items.Add(li2); dropDownListId.Items.Add(li3);
Hope that everyone is still with me. What I want to do is to on the Autopostback is take the string "foo" and convert that to Types.foo - without using a switch (as the enumerated values are generated from a database and may change).
I hope that makes sense? Any idea where to even start?
Sure:
Types t;
if(Enum.TryParse(yourString, out t)) // yourString is "foo", for example
{
// use t
}
else
{
// yourString does not contain a valid Types value
}
There's also an overload that takes a boolean that allows you to specify case insensitiveness:
http://msdn.microsoft.com/en-us/library/dd991317.aspx
Enum.TryParse is new in .NET 4. If you're stuck on a previous version, you'll have to use the non-typesafe Enum.Parse method (which throws an exception in case of conversion failure, instead of returning false), like so:
try
{
Types t = (Types)Enum.Parse(typeof(Types), yourString);
// use t
}
catch(ArgumentException)
{
// yourString does not contain a valid Types value
}
Enum.Parse also has an overload for case insensitiveness.
So, you want: Enum.Parse(typeof(Types), postbackValue)
or did I miss something?
If I understood correctly, you can do:
Types fooEnum = Enum.Parse(typeof(Types), "foo");
See: http://msdn.microsoft.com/en-us/library/essfb559.aspx