var quantSubset =
from userAns in userAnalysis.AllUserAnswers
join ques in userAnalysis.AllSeenQuestions on userAns.QID equals ques.QID
where (ques.QuestionType == "QT")
select new {
QuestionLevel = ques.LevelID,
TimeTaken = userAns.TimeTaken,
Points = userAns.Points,
UsedWeapon = (userAns.UsedBy2 && userAns.UsedHint),
WasCorrect = userAns.WasCorrect.HasValue ? userAns.WasCorrect.Value : null
};
In my select expression I want to select a nullable type WasCorrect (last part of the expression) but apparently I cannot do it the way I am currently trying.
How can I get WasCorrect as nullable type
I tried ?WasCorrect but that also doesnt gives error in Visual Studio.
You need to cast the null value to the nullable type explicitly:
WasCorrect = userAns.WasCorrect.HasValue ?
userAns.WasCorrect.Value : (TheTypeName?)null
Otherwise C# won’t know which type the conditional expression should be.
Apart from that, the code is completely redundant. You can simply write:
WasCorrect = userAns.WasCorrect
You absolutely must be able to write
select new { WasCorrect = userAns.WasCorrect }
if userAns.WasCorrect is Nullable<bool>.
This code executes without a problem:
class Test {
public bool? NullableBool { get; set;}
}
class MainClass
{
public static void Main ()
{
Test t1 = new Test { NullableBool = true };
var a1 = new { NB = t1.NullableBool };
Test t2 = new Test { NullableBool = null };
var a2 = new { NB = t2.NullableBool };
}
}
Related
I am working on a method that can pass in 2 objects of the same type and it will compare the two. In the end I am planning on overloading it to accept property names etc to evaluate only those or exclude only those form the evaluation. That will have to happen after I get the basic full compare working.
I have be been able to compare value types and reference types. Where I am stuck is being able to compare properties that are Enumerable. The else statement is what I cannot get to work correctly.
public static void CompareObjects<T>(T obj1, T obj2)
{
foreach (var property in typeof(T).GetProperties())
{
var obj1Prop = property.GetValue(obj1);
var obj2Prop = property.GetValue(obj2);
//for value types
if (property.PropertyType.IsPrimitive || property.PropertyType.IsValueType || property.PropertyType == typeof(string))
{
if (obj1Prop != obj2Prop)
Console.WriteLine($"Object 1 {property.Name}:{obj1Prop}{Environment.NewLine}Object 2 {property.Name}:{obj2Prop}{Environment.NewLine}");
}
//for objects
else if (property.PropertyType.IsClass && !typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
dynamic obj1PropObj = Convert.ChangeType(obj1Prop, property.PropertyType);
dynamic obj2PropObj = Convert.ChangeType(obj2Prop, property.PropertyType);
CompareObjects(obj1PropObj, obj2PropObj);
}
//for Enumerables
else
{
var enumerablePropObj1 = property.GetValue(obj1) as IEnumerable;
var enumerablePropObj2 = property.GetValue(obj2) as IEnumerable;
if (enumerablePropObj1 == null) continue;
if (enumerablePropObj2 == null) continue;
var list1 = enumerablePropObj1.GetEnumerator();
var list2 = enumerablePropObj2.GetEnumerator();
while (list1.MoveNext())
{
list2.MoveNext();
CompareObjects(list1.Current, list2.Current);
}
}
}
}
This iterates through the list but without the values. The setup that I am using to implement this is as follows:
static void Main(string[] args)
{
var student1 = new Student
{
FirstName = "John",
LastName = "Smith",
Age = 18,
DateOfBirth = DateTime.Parse("1989/03/03"),
Job = new Job
{
Company = "CompanyOne",
Title = "Supervisor"
},
PhoneNumbers = new List<PhoneNumber>
{
new PhoneNumber
{
Number = "8675309",
Label = "Home"
},
new PhoneNumber
{
Number = "1234567",
Label = "Work"
}
}
};
var student2 = new Student
{
FirstName = "Theodore",
LastName = "Smith",
Age = 22,
DateOfBirth = DateTime.Parse("1990/03/03"),
Job = new Job
{
Company = "CompanyOne",
Title = "Manager"
},
PhoneNumbers = new List<PhoneNumber>
{
new PhoneNumber
{
Number = "8675308",
Label = "Home"
},
new PhoneNumber
{
Number = "1234567",
Label = "Work"
}
}
};
CompareObjects(student1, student2);
Console.WriteLine("Done");
Console.ReadKey();
}
Your problem is that your method is generic. When you call it on the sub-collections, the type you are using for the comparison is System.Object, which of course has no interesting properties to compare.
Change your method declaration and the preamble of the method:
public static void CompareObjects(object obj1, object obj2)
{
if (obj1.GetType() != obj2.GetType())
{
return;
}
foreach (var property in obj1.GetType().GetProperties())
{
...
Note that with this approach, you also do not need the dynamic and ChangeType() code.
Finally, you may want to consider changing your inequality comparison so that instead of using the != operator it uses the Equals() method:
if (!obj1Prop.Equals(obj2Prop))
{
Console.WriteLine($"Object 1 {property.Name}:{obj1Prop}{Environment.NewLine}Object 2 {property.Name}:{obj2Prop}{Environment.NewLine}");
}
Even when the method was generic, that would be a good idea; while one is supposed to implement the equality and inequality operators if one overrides Equals(), that doesn't always happen. When the method is non-generic, of course you won't even get operator overloads for the specific types (at least not without a lot of extra work).
(I guess you could instead of the above use the same dynamic/ChangeType() approach you use for the non-enumerable properties, using e.g. list1.Current.GetType() as the type instead of property.PropertyType; that could allow the method to remain generic. But there's so much extra overhead to dynamic and ultimately it will all come back down to executing the same code, I just don't see the point in doing it that way.)
Consider this hierarchy of classes.
class Event
{
public Attendees[] AttendeesList;
}
class Attendees
{
public ComplexProperty Property;
public object Value;
}
class ComplexProperty
{
}
class Program
{
static void Main(string[] args)
{
// There are constants.
ComplexProperty constproperty = new ComplexProperty();
object constValue = 5;
// consider this linq query:
Event evnt = new Event();
var result = evnt.AttendeesList.Any((attnds) => attnds.Property == constproperty && attnds.Value == constValue);
// I want to create an Expression tree for above linq query. I need something like this:
ParameterExpression parameter = Expression.Parameter(typeof(Attendees));
Expression left = Expression.Property(parameter, typeof(ComplexProperty).GetProperty("Property"));
// complete this piece.......
}
}
I want to create a Linq.Expressions.Expression for evnt.AttendeesList.Any((attnds) => attnds.Property == constproperty && attnds.Value == constValue);
this linq query. How to query collection with Linq.Expressions looks similar, but I have Any in my linq expression.
Please help.
This will give you a start:
ParameterExpression parameter = Expression.Parameter(typeof(Attendees));
Expression left = Expression.Equal(Expression.Property(parameter, "Property"), Expression.Constant(constproperty));
var objType = constValue == null ? typeof(object) : constValue.GetType();
var convertLeft = Expression.Convert(Expression.Property(parameter, "Value"), objType);
var convertRight = Expression.Convert(Expression.Constant(constValue), objType);
Expression right = Expression.Equal(convertLeft, convertRight);
Expression joined = Expression.And(left, right);
var anyMethod = typeof(Queryable).GetMethods().Where(m => m.Name=="Any" && m.GetParameters().Count() == 2).First().MakeGenericMethod(typeof(Attendees));
var call = Expression.Call(anyMethod, Expression.Constant(evnt.AttendeesList, typeof(IQueryable<Attendees>)), Expression.Lambda(joined, parameter));
I changed Value to type int for ease of use. If you want to keep it as an object, you will need to add a Expression.Convert() call in the right Expression.
Please, take a look at following proof of concept:
private class Model
{
public string Data { get; set; }
public bool NonEmpty() { return Data.Length > 0; }
}
private static Func<Model, bool> Compile()
{
var type = typeof(Model);
var expr = Expression.Parameter(typeof(Model));
var subarg1 = Expression.Property(expr, type.GetProperty("Data"));
var subarg2 = Expression.Constant(null);
var arg1 = Expression.NotEqual(subarg1, subarg2);
var arg2 = Expression.Call(expr, type.GetMethod("NonEmpty"));
var tree = Expression.And(arg1, arg2); // Data != null && NonEmpty()
var func = Expression.Lambda<Func<Model, bool>>(tree, expr).Compile();
return func;
}
var model = new Model {Data = null};
var standardTest = model.Data != null && model.NonEmpty(); // returns false
var exprTreeTest = Compile().Invoke(model); // throws null ref exception
Because the first operand evaluates to false, the result of the AND operation is false no matter what the value of second one may be. That's why the second operand shouldn't be computed. While C# compiler does it correctly, expression library does not.
How to fix my code to respect the short-circuit evaluation?
Expression.And represents the non-short circuiting AND operator (&).
Expression.AndAlso represents the short circuiting AND operator (&&).
I have the class:
class Person
{
public string Name { get { return "Antonio"; } }
}
and the Code:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>( );
var observCol = uncknownObject.GetType( );
var x = ( ( dynamic )observCol ).GenericTypeArguments[ 0 ];
var y = observCol.GetProperty( "GenericTypeArguments" );
var instance = ( Person )Activator.CreateInstance( x );
Console.WriteLine( instance.Name ); // Print Antonio!!!
why does y == null ?
Note the picture:
the debugger shows that the property GenericTypeArguments should exist and the code shows the opossite. It can be proven that the debugger is right and that property exist because then how come x is not null. If that property exists then why y is equal to null!!!???
Edit
Thanks to Ani I now have:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>();
var observCol = uncknownObject.GetType();
var genTypeArgsProperty = typeof(Type).GetProperty("UnderlyingSystemType");
var genTypeArgsValue = (genTypeArgsProperty.GetValue(observCol, null));
var f = genTypeArgsValue.GetType().GetMethod("GetGenericArguments");
IEnumerable<object> result = (IEnumerable<object>)f.Invoke(genTypeArgsValue, null);
var x = result.FirstOrDefault();
var instance = Activator.CreateInstance( (Type)x );
In case of curios why I needed that functionality click here
I don't really understand what you're trying to accomplish with all this meta-meta-reflection, but you seem to have misunderstood what Type.GetProperty does. It gets meta-data for a property on the actual type represented by the System.Type instance (in this case, ObservableCollection<Person>). It does not get meta-data for a property declared on System.Type itself, unless of course you call it on a System.Type representing System.Type itself.
In your case, y is null since ObservableCollection<Person> does not have a property named "GenericTypeArguments".
Try this instead:
var genTypeArgsProperty = typeof(Type).GetProperty("GenericTypeArguments");
var genTypeArgsValue = (Type[]) (genTypeArgsProperty.GetValue(observCol, null));
var onlyTypeArgValue = genTypeArgsValue.Single();
This code works with net framework 4:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>();
var observCol = uncknownObject.GetType();
var x = ((dynamic) observCol).UnderlyingSystemType.GetGenericArguments()[0];
var y = observCol.GetGenericArguments();
var instance = (Person)Activator.CreateInstance(x);
Console.WriteLine(instance.Name); // Print Antonio!!!
I know that this can be rewritten using a lambda expression. But I cant seem to figure it out. does anyone have an opinion on how it should be written using a lambda.
foreach (var _systemItem in _systemData)
{
foreach (var _institutionItem in _institutionData)
{
if (_systemItem.LookupValue == _institutionItem.OriginalSystemLookupValue)
{
_values.Add(new LookupValue()
{
DisplayText = _institutionItem.LookupText,
Value = _institutionItem.LookupValue
});
}
else
{
_values.Add(new LookupValue()
{
DisplayText = _systemItem.LookupText,
Value = _systemItem.LookupValue
});
}
}
}
Like this:
values.AddRange(from s in _systemData
from i in institutionData
select s.LookupValue == i.OriginalSystemLookupValue ?
new LookupValue {
DisplayText = _institutionItem.LookupText,
Value = _institutionItem.LookupValue
}
: new LookupValue {
DisplayText = _systemItem.LookupText,
Value = _systemItem.LookupValue
}
);
Is _values a List<LookupValue> which is empty to start with? If so, that look might look like this:
_values = (from x in _systemData
from y in _institutionData
let item = x.LookupValue == y.OriginalSystemLookupValue ? x : y
select new LookupValue { DisplayText = item.LookupText,
Value = item.LookupValue })
.ToList();
That assumes that _systemItem and _institutionItem are the same type. If they're unrelated types, you might want to give them a common interface that defines LookupText and LookupValue (or even a ToLookupValue method) and then cast one of the operands in the conditional operator to the interface. For example:
_values = (from x in _systemData
from y in _institutionData
let item = x.LookupValue == y.OriginalSystemLookupValue
? (ILookupSource) x : y
select item.ToLookupValue())
.ToList();
Sure, I have an opinion. I'd write it like this:
var pairs = _systemData.SelectMany(s =>
_institutionData.Select(i => new { System = s, Institution = i }));
_values.AddRange(pairs.Select(x =>
{
bool match = x.System.LookupValue == x.Insitution.OriginalSystemLookupValue;
return match ? new LookupValue(x.Institution) : new LookupValue(x.System);
}));
And move the object initializers for LookupValue into real constructors that take an Institution or System.