Please explain this convert extension method - c#

I'm trying to make sense of the code below, can someone please explain to me (in simple terms) how and what gets converted. In particular this part is confusing me (this IEnumerable> values)
Code:
public static class ConvertExtensions
{
public static IEnumerable<TTarget> ConvertAll<TSource, TTarget>(this IEnumerable<IConvertModel<TSource, TTarget>> values) => values.Select(value => value.Convert);
}

It's basically, for every value in a collection, call the T.Convert function, (where T is the target type) and return another collection of the converted values.
It doesn't DO any conversion, it hands the conversion off to a different function depending on the output type.
It's a shorthand way of doing something like this:
var convertedValues = new List<TTarget>();
foreach(var value in values)
{
var convertedValue = value.Convert();
convertedValues.Add(convertedValue);
}
return convertedValues;

Related

List.Foreach() complains cannot convert from 'void' to 'object'

When I tried to run the following code, it tells me the 'cannot convert from 'void' to 'object' on the last line, does anyone know what is wrong with the code?
public static void Main(string[] args)
{
string s = "asfdsanfdjsajfois";
Dictionary<char, int> dict = new Dictionary<char, int>();
s.ToCharArray().ToList().ForEach(a => {
dict[a] = (dict.ContainsKey(a)) ? dict[a]+1 : 1;
});
pln(dict.Keys.ToList().ForEach(a => Console.WriteLine(dict[a])));
}
The problem is clear without providing any more information:
dict.Keys.ToList().ForEach(a => Console.WriteLine(dict[a])) is a statement that doesn't return anything void, and you're passing that to the pln function, that functions accepts and an argument of type object. You need to pass it an object for that type in order to make the compiler happy and for the code to make sense.
Take a look into this part: .ForEach(a => Console.WriteLine(dict[a]); through this you are iterating through each keys in the Dictionary and print them to the console. Actually the Console.WriteLine() method's return type is void which means it is not returning anything. But you are trying to pass something to a method called pln But it is not specified in the question that how the method is defined or what's the value you are expected in that method.
Actually you need not to iterate through keys and then collect values, you can directly fetch values like this:
dict.Select(x=>x.Value).ToList()
If you need to pass each values to the plan method then you should modify the pln method signature like the following:
private static void pln(int p)
{
Console.WriteLine(p);
// Do something here
}
And for this the query will be like dict.ToList().ForEach(x => pln(x.Value));
If you want to pass the values as List then the method signature will be :
private static void pln(List<int> p)
{
// Do something here
}
And for this the query will be like pln(dict.Select(a => a.Value).ToList());

Cannot implicitly convert type System.Collections.Generic.Dictionary<System.Tuple<int,int,string>, AnonymousType#1>

I have the following dictionary in a method:
var nmDict = xelem.Descendants(plantNS + "Month").ToDictionary(
k => new Tuple<int, int, string>(int.Parse(k.Ancestors(plantNS + "Year").First().Attribute("Year").Value), Int32.Parse(k.Attribute("Month1").Value), k.Ancestors(plantNS + "Report").First().Attribute("Location").Value.ToString()),
v => {
var detail = v.Descendants(plantNS + "Details").First();
return
new
{
BaseHours = detail.Attribute("BaseHours").Value,
OvertimeHours = detail.Attribute("OvertimeHours").Value
};
});
I need to return nmDict. The problem is that I cannot figure out how to label my method signature. I have tried the following:
protected IDictionary<XElement, XElement> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
The above gives me this error:
Cannot implicitly convert type System.Collections.Generic.Dictionary<System.Tuple<int,int,string>,AnonymousType#1>' to 'System.Collections.Generic.IDictionary<System.Xml.Linq.XElement,System.Xml.Linq.XElement>'. An explicit conversion exists (are you missing a cast?)
protected IDictionary<Tuple, XElement> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
gives me this error:
'System.Tuple': static types cannot be used as type arguments
I do not know what to do.
The short answer: You can't return anonymous types from a function.
The long answer: Your dictionary's value type is anonymous {BaseHours, OvertimeHours} which cannot be returned from a function or passed as an argument (except as an object, but that does nobody any good unless you go through the hassle of reflecting into it). Either define a class/struct with BaseHours and OvertimeHours in it, or use a tuple. The former is probably slightly better because you can keep the names BaseHours and OvertimeHours; with a tuple you just get Value1 and Value2.
If you are using C# 4.0 than you can return the anonymous via dynamic type. So your method signature would look like this
protected IDictionary<Tuple<int,int,string>, dynamic> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
And through the dynamic object you can find the properties at run time.
Hope this will help you.
When you call the ToDictionary method, the resulting dictionary's type has little to do with the type of elements in your source sequence. It's defined entirely by the data types returned by the key and value expressions you supply to the call. For example, if you were to call:
xelem.Descendants(plantNS + "Month").ToDictionary(
k => int.Parse(k.Attribute("Year").Value),
v => k.Attribute("Year).Value
);
You would get an IDictionary<int, string> because that's what your two expressions returned. To return that from a method, you just need to construct the correct type, based on your expressions.
Your first one is easy:
k => new Tuple<int, int, string>(...)
The second one, though, is going to be a problem. The values in your dictionary are of an anonymous type: you return a new { } without specifying a concrete type name for that value. In general, that is going to make it impossible for you to use that dictionary as a return value or parameter. (It can be done, using some very strange-looking generic techniques, but I wouldn't recommend it.)
The first thing you'll need to do, then, is make a concrete type to hold your values, e.g.
public class HoursContainer
{
public string BaseHours { get; set; }
public string OvertimeHouse { get; set; }
}
and change your Linq query appropriately:
var detail = v.Descendants(plantNS + "Details").First();
return new HoursContainer
{
BaseHours = detail.Attribute("BaseHours").Value,
OvertimeHours = detail.Attribute("OvertimeHours").Value
};
Once you've done this, your dictionary will have a concrete type based on the types of things you specified when you created it:
IDictionary<Tuple<int, int, string>, HoursContainer>
(Note: You could also just use another Tuple<int, int> or whatever here, if you wanted, but the resulting generic type would get unwieldy very fast.)

How to replace the string value in extension method for lambda

I would like to replace "PKMvrMedsProductIssuesId" for something like x=>x.PKMvrMedsProductIssueId or anything that is not based on a string. Why? Because if the database people choose to rename the field my program would crash.
public static SelectList MvrMedsProductErrors(this SelectList Object)
{
MedicalVarianceEntities LinqEntitiesCtx = new MedicalVarianceEntities();
var ProductErrorsListBoxRaw =
(
from x in LinqEntitiesCtx.ViewLookUpProductIssuesErrorsNames
select x
);
Object = new SelectList(ProductErrorsListBoxRaw, "PKMvrMedsProductIssuesId", "MvrMedsProductIssuesErrorsNames");
return Object;
}
You're using a SelectList. In order to call that constructor, you must have a string. Any change we could propose will still result in a string (from somewhere) being passed into that constructor.
The good news is: that string can come from anywhere. It can come from config, from the database... where ever you like.
I don't know the exact context here (what exactly "PKMvrMedsProductIssuesId" is) , but you can for example use such helper method:
public static string GetPropertyAsString<T>(Expression<Func<T, object>> expression)
{
return GetPropertyInfo(expression).Name;
}
To use an expression to get string:
GetPropertyAsString<MyType>(x => x.MyTypeProperty);
('MyTypeProperty' is your 'PKMvrMedsProductIssuesId' any 'MyType' one of your types where you may have your property defined)

Get actual return type from a Expression<Func<T, object>> instance

I have a method that accepts a Expression<Func<T, object>> instance. I want to get at the actual data type being returned by a specific expression instance, rather than object.
I can get it to work for direct property references, so if I pass in the expression x => x.IntegerProperty I can get a Type reference for an integer. This approach requires converting it to a MemberExpression.
However, I can't get it to work for arbitrary expressions. For instance, if the expression is x => x.IntegerProperty.ToString() I want to get a Type reference for a string. I can't compile this to a MemberExpression, and if I just .Compile() it and check the return type I get "object".
How can I look at the specific expression instance and derive the actual return type?
Something like this might do the trick. It probably doesn't cover every possibility, but it's a start.
public static Type GetObjectType<T>(Expression<Func<T, object>> expr)
{
if ((expr.Body.NodeType == ExpressionType.Convert) ||
(expr.Body.NodeType == ExpressionType.ConvertChecked))
{
var unary = expr.Body as UnaryExpression;
if (unary != null)
return unary.Operand.Type;
}
return expr.Body.Type;
}
While not impossible, this is particularly difficult. It would require walking the expression tree and doing some potentially complex logic. For example, what would you want to see if I passed in the following expression?
Func<bool, object> expr = switch => switch ? 1 : "False";
This method could either return an int or a string.
Now, you might be able to make more headway by offloading some of this logic on the compiler. You could change your method parameter from Func<T, object> to Func<T, TReturn> and use typeof(TReturn) within the method to determine what the compiler decided the return type of the expression was.
Of course, in the case of my example, you'll still be working against object. But, your example of x => x.IntegerProperty.ToString() will yield string, which is what you're looking for.
Bit of a cheeky way (and it involves actually invoking the Func), but you can do this:
using System;
class Program
{
static Func<T,object> MakeFunc<T>()
{
return x => 23;
}
static Type GetReturnType<T>(Func<T,object> f)
{
return f(default(T)).GetType();
}
static void Main(string[] args)
{
Type t = GetReturnType(MakeFunc<string>());
Console.WriteLine(t);
}
}
It's not guaranteed to work in all situations, I should add - particularly if the default(T) isn't a valid parameter to the Func. But it's a potential starting point at least.

C# What construct am I Looking for Lamba / Expression / Func / Reflection for runtime property substitution?

I've a method on a generic base class that I want to execute for all superclasses of it
The logic is something like:
BuildAverageDateStats(List<type> items, DateProperty1 exp, DateProperty2 exp2)
{
return new Stat{
Value = items.Average(c => (c.DateProperty2 - c.DateProperty1).Milliseconds)
};
}
myobject.BuildAverageDateStats(list, () => c.QueuedDate, () => c.CompletedDate);
myobject.BuildAverageDateStats(list, () => c.ActionedDate, () => c.CompletedDate);
I think I need expressions, but not sure how...
I could send it in as Func i.e. Value = items.Average(c => myfunc(c)) but looking for a property substitution example.
Stat BuildAverageDateStats<U>(List<type> items, Func<U, double> exp)
where U:type
{
return new Stat{
Value = items.OfType<U>().Average(exp);
};
}
You can call it like this
BuidlAverageDateStats<Dog>(items, d=>d.Age - d.Height);
Though my example doesn't make sense.
If you are really only ever going to use one of the three DateTime properties that you have right now, I would keep the method signature the way you have it right now.
To make things neater, make some public static readonly delegate fields on your class for your properties, and use those, instead of writing the same expression time and time again:
public static readonly DateSelector Date1Property = delegate(CompareTest c) { return c.Date1; };
public static readonly DateSelector Date2Property = delegate(CompareTest c) { return c.Date2; };
public static readonly DateSelector Date3Property = delegate(CompareTest c) { return c.Date3; };
If, on the other hand, you expect inheriting classes to implement more properties than the three you have right now, you could consider passing in the properties as String and using the Dynamic Linq Library (and build a dynamic expression that returns the property) or a DynamicMethod to return your property. Both would have the benefits of reflection with the painful performance. If you need it, I have some code laying around for that.
Type safety will be out the window though, so I wouldn't use it unless necessary, and it sounds like it isn't.
Menno
static Stat BuildAverageDateStats<T>(List<T> items, string pname1, string pname2){
return new Stat {
Value = items.Average( c =>
{
var ty = c.GetType();
var pv1 = (dynamic)ty.GetProperty(pname1).GetValue(c,null);
var pv2 = (dynamic)ty.GetProperty(pname2).GetValue(c,null);
return pv2 - pv1;
})
};
}

Categories