Would it be possible to create code like this:
private static string GetInsertString<TDto>()
{
var type = typeof(TDto);
var properties = type.GetProperties().Where(Where);
var tableName = type.Name;
return string.Format("INSERT INTO {0} ({1}) VALUES ({2});",
tableName,
string.Join(",", properties.Select(x => x.Name).ToArray()),
string.Join(",", properties.Select(x => string.Format("#{0}", x.Name.ToLower())).ToArray()));
}
that works with anonymous types like this:
var point = new { X = 13, Y = 7 };
PS:
Output would be:
INSERT INTO Anonymous (X, Y) values (13, 7)
of course you may want to provide the table name.
You won't be able to specify the type parameter with an anonymous type, but if you pass it an object as a parameter, you can use type inference to get a hold of the type:
private static string GetInsertString<TDto>(TDto dto)
{
var type = typeof(TDto);
var propertyNames = type.GetProperties().Where(Where).Select(x => x.Name);
return string.Format("INSERT INTO {0} ({1}) VALUES ({2});",
type.Name,
string.Join(",", propertyNames),
string.Join(",", propertyNames.Select(x => string.Format("#{0}", x.ToLower())));
}
Then call the method: var insertString = GetInsertString(new { X = 13, Y = 7 });
It is very hard to use anonymous types with a ...<T>() method. The main way of doing that involves the by example hack, i.e.
var dummy = new { X = 13, Y = 7 };
Foo(dummy); // for Foo<T>(T obj)
or more succinctly:
Foo(new { X = 13, Y = 7 });
which uses generic type inference to deduce that T here is the anonymous type. Foo<T>(T obj) could either be your actual method, or could be a method that in turn calls GetInsertString<TDto>(), i.e.
// overload that takes an example object as a parameter
private static string GetInsertString<TDto>(TDto example) {
return GetInsertString<TDto>();
}
You could also probably combine the two:
private static string GetInsertString<TDto>(TDto example = null) {
.. your code ..
}
and pass the example only when it is necessary.
However, the "by example" approach is brittle and susceptible to breaking. I strongly recommend that you simply define a POCO instead:
public class MyType {
public int X {get;set;}
public int Y {get;set;}
}
and use GetInsertString<MyType>.
Assuming you're using .net 4.0 or above, you can use dynamic and ExpandoObject like this:
private static string GetInsertString(dynamic obj)
{
var expando = (ExpandoObject)obj;
return string.Format("INSERT INTO {0} ({1}) VALUES ({2});",
"tableName",
string.Join(",", expando.Select(x => x.Key)),
string.Join(",", expando.Select(x => x.Value is string ? "'" + x.Value + "'" : x.Value.ToString())));
}
And then:
dynamic o = new ExpandoObject();
o.a = 10;
o.b = "hello";
var s = GetInsertString(o);
Now s is INSERT INTO tableName (a,b) VALUES (10,'hello');.
This is only a draft you have to do some work to get a correct insert string.
You can use anonymous objects with generic methods as long as the compiler can resolve the type. For instance, if it can be resolved from a parameter. Like this:
private static string GetInsertString<TDto>(TDto someObject) {
var type = typeof(TDto);
var properties = type.GetProperties(); // Removed .Where(Where) since it didn't compile
var tableName = type.Name;
return string.Format(
"INSERT INTO {0} ({1}) VALUES ({2});",
tableName,
string.Join(",", properties.Select(x => x.Name).ToArray()),
string.Join(",", properties.Select(x => string.Format("#{0}", x.Name.ToLower())).ToArray())
);
}
var point = new { X = 13, Y = 7 };
var insertSql = Test.GetInsertString(point);
// Results in: INSERT INTO <>f__AnonymousType0`2 (X,Y) VALUES (#x,#y);
Related
I have this code that works but I would like to simplify it. I tried to string each .ForEach together but seems like that's not possible. Can someone suggest how I can combine these:
phraseSources
.ToList()
.ForEach(i => i.JishoExists = "");
phraseSources
.ToList()
.ForEach(i => i.CommonWord = "");
phraseSources
.ToList()
.ForEach(i => i.JishoWanikani = null);
phraseSources
.ToList()
.ForEach(i => i.JishoJlpt = null);
Because of ForEach first parameter is Action<T> which mean you can use a delegate method with one parameter.
you can try to use big parentheses on the delegate parameter.
phraseSources
.ToList()
.ForEach(i => {
i.JishoExists = "";
i.CommonWord = "";
i.JishoWanikani = null;
i.JishoJlpt = null;
});
I think that foreach (not ForEach) is the best tool for this job.
foreach(var i in phraseSources)
{
i.JishoExists = "";
i.CommonWord = "";
i.JishoWanikani = null;
i.JishoJlpt = null;
}
ToList().ForEach can lead to unexpected results. Consider the following example.
public class XClass {public string A {get; set;}}
public struct XStruct {public string A {get; set;}}
public static void Main(string[] args)
{
var array1 = new []{new XClass{A="One"}, new XClass{A="Two"}};
var array2 = new []{new XStruct{A="One"}, new XStruct{A="Two"}};
array1.ToList().ForEach( x => x.A = "XXX");
array2.ToList().ForEach( x => x.A = "XXX");
Console.WriteLine(array2[0].A); // Ooops: it's still "One"
}
Declaring a list of objects:
List<object> result = new List<object>();
and a list of int to store the ids:
List<int> ids = new List<int>();
I want to store in result objects containing the pair (string, list of int).
It works fine for the pair (string, int) but I want that when there are 2 identical strings to have only one object and the int values to be stored in a list.
ex: {pars = "xxx", id = 1} , {pars = "xxx", id = 2} becomes {pars = "xxx", id = (1,2 )}
For doing the initial functionality, I use a foreach through an object from which I take the string(pars) and the id:
foreach (dataBinding in myData)
{
var x = string.Join(" ", dataBinding.Params.Select(p => p.myDescription));
result.Add(new { pars = x, id = dataBinding.Id });
}
there could be more strings in Params, that's why I use the join.
As it is here it works by creating objects having the form (string, int). But my aim is to make it (string, list of int) and if there are two objects with same string to combine them as I wrote before.
I tried to add ids list as the second property of the object but probably I'm not doing it correctly.
result.Add(new { pars = x, ids = dataBinding.Id });
You can use LINQ, especially GroupBy:
Dictionary<string, List<int>> descriptionIDs = myData
.GroupBy(x => x.myDescription)
.ToDictionary(g => g.Key, g => g.Select(x => x.Id).ToList());
Now you have even a dictionary, not just a strange List<object> that contains anonymous types.
As someone mentioned, you can also use ToLookup which i'd also prefer:
var descriptionLookup = myData.ToLookup(x => x.myDescription);
Now you can get the ID-List easily:
var result = descriptionLookup.Select(g => new { pars = g.Key, ids = g.Select(x=> x.Id).ToList() }).ToList():
Perhaps I am not understanding the scenario fully but I suspect using the following would server your purpose.
List<Dictionary<string, List<int>>>
When the key doesn't exist you add it and when it does you just add to the List.
Below program depicts the current generic collection type, also allow to add a new value if Key Already exists.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
MyProgram p = new MyProgram();
p.Add("First" , 5);
p.Add("Second" , 8);
p.Add("Third" , 9);
p.Add("First" , 6);
p.Add("First" , 7);
p.PrintDictionary();
}
}
public class MyProgram
{
private Dictionary<string, List<int>> dict = new Dictionary<string, List<int>>();
public void Add(string key, int value)
{
if (dict.ContainsKey(key))
{
dict[key].Add(value);
}
else
{
dict.Add(key, new List<int>() {value});
}
}
public void PrintDictionary()
{
foreach(var keyValue in dict)
{
Console.WriteLine("Key : " + keyValue.Key);
foreach(var val in keyValue.Value)
{
Console.WriteLine(string.Format("\t Value : {0}", val));
}
}
}
}
Output :
Key : First
Value : 5
Value : 6
Value : 7
Key : Second
Value : 8
Key : Third
Value : 9
Check this Live Fiddle.
In JavaScript, I can call a function like so:
x = myFunction({"meetingID": 2, "meetingRoom": "A103"});
myFunction() then receives an object which I can parse with JSON, or just by referencing the object's properties:
function myFunction( args ) {
var x = args.meetingID;
}
Is there any such similar construct in C#? Are there such things as "inline objects", or "on the fly objects"?
You can use anonymous type in conjunction with dynamic keyword.
void MyFunction(dynamic args)
{
var x = args.MeetingId;
}
MyFunction(new { MeetingId = 2, MeetingRoom = "A103" });
Beware - this works different from javascript. If object passed to MyFunction doesn't contain property MeetingId, you'll get exception at runtime.
You could use a dictionary
public static void Main()
{
myFunction(new Dictionary<string, object>()
{
{ "meetingID", 2},
{ "meetingRoom", "A103"}
}
);
}
public static void myFunction(Dictionary<string,object> args)
{
var x = args["meetingID"];
}
Just a small suggestion .. if possible, it will be safer to use optional parameters instead:
string myFunction( int meetingID = 0, string meetingRoom = null ) {
var x = meetingID;
}
then you can use it like :
var x = myFunction( meetingID: 2, meetingRoom: "A103" );
var y = myFunction( meetingRoom:"A103" ); // order doesn't matter if you specify the parameter name
var z = myFunction( 3, "B109" );
var _ = myFunction();
I have this code :
(simple enum which has values for a,b,c ...[0,1,2] , and i want to show for each looped number - its corrosponding enum in a final list).
public enum ENM
{
a,b,c
}
void Main()
{
var e = Enumerable.Range(0,3).Select(myCounter=>new {
final=((Func<int,ENM>)delegate (int i)
{
return (ENM)i;
})(myCounter)
}).ToList();
this is fine and working.
Is there any solution without writing delegate(int i) {...}?
p.s. of course I can just write (ENM)i but the question is for learning
how to write ( in different ways ) the auto-executed methods.
Why not
Enumerable.Range(0,3).Select(c=>(ENM)c).ToList()
or am I missing some reason for the over complexity?
var e = Enumerable.Range(0, 3).Select(myCounter => new
{
final = ((Func<int, ENM>)(
i=>{
return (ENM)i;
/* More code could be here */
}))(myCounter)
}).ToList();
is about as tight as you will get if you want the same mess :)
var e = Enum.GetNames(typeof(ENM)).Select((e, i) => new { final = e, index = i }).ToList();
OR
var EnumNames = Enum.GetNames(typeof(ENM));
var EnumValues = Enum.GetValues(typeof(ENM)).Cast<ENM>().Select(e => (int)e);
var result = EnumNames.Zip(EnumValues, (n, v) => new { final = n, index = v });
There's a specific method in System.Enum for doing exactly this:
var arr = Enum.GetValues(typeof(ENM));
To get it into a List<ENM>:
var lst = arr.Cast<ENM>().ToList();
I am using the Linq DynamicQuerable code. I have an array of integers and a string representing the field I want to use as the excluding filter.
For example
IQuerable GetItemsWithoutExcluded(IQuerable qry, string primaryKey, List<int> excludedItems) {
// psuedo code
return qry.Where("p=>! p.primaryKey in excludedItems");
}
Any idea how I would accomplish this using DynamicQuerable?
You can do this without dynamic-LINQ. Dynamic-LINQ is not a full fledged citizen of the framework. And by changing the way you accomplish this task you can use a more effective filter. The way you have it now the method needs to be called for each exclusion.
Try something like this instead
List<int> allKeys = new List<int>{1,2,3,4,5,6};
List<int> excluded = new List<int>{ 1, 2, 3 };
var query = from included in allKeys
where !excluded.Contains(included)
select included;
foreach (var item in query)
Console.WriteLine(item);
I would implement this like the following using ordinary LINQ:
public static IQueryable<T> Exclude<T>(this IQuerable<T> qry, Expression<Func<T, int>> keySelector, List<int> excludedItems)
{
var keyGroups = qry.GroupBy(keySelector);
var includedGroups = keyGroups.Where(g => !excludedItems.Contains(g.Key));
return includedGroups.SelectMany(g => g);
}
Then it can be used like so:
public class MyClass
{
public int Key { get; set; }
}
IQueryable<MyClass> source = // Get source data (DataContext/ObjectContext/ISession etc.)
var excludedKeys = new List<int> { 1, 3, 11 };
var result = source.Exclude(item => item.Key, excludedKeys);
Update for Dynamic LINQ
IQuerable GetItemsWithoutExcluded(IQuerable qry, string primaryKey, List<int> excludedItems)
{
if(excludedItems.Count == 0)
return qry;
var keyChecks = excludedItems.Select(i => String.Format("p.{0} != {1}", primaryKey, i));
var constraint = String.Join(" && ", keyChecks )
return qry.Where("p => " + constraint);
}