Why in C# 3 I can do this:
DataTable dt = new DataTable() {
Columns = { "1", "2", "3" } };
But I can't do this:
class Person {
int Id { get; set; }
}
class Program {
static void Main(string[] args)
{
var v = new List<Person> { 1, 2, 3 };
}
}
Because there is not implicit conversion from int to Person. If you were to define an implicit conversion for Person, that should work:
http://msdn.microsoft.com/en-us/library/z5z9kes2(v=VS.100).aspx
Note in the example that a double value is implicitly convertable to a Digit type. You could define an implicit conversion for int to Person.
Neither 1, nor 2, nor 3 are Person objects.
You could, though try:
var people = new List<Person>() { new Person() { Id = 1 }, new Person() { Id = 2 } , new Person() { Id = 3 } };
Because and integer is not the same as a Person object, and the Id is a property that needs to be assigned to.
var v = new List<Person>();
for (i = 1; i <= 3; i++) {
var p = new Person() {
Id = i;
}
v.Add(p);
}
You need to call the constructor to actually instance it. In your code you are basically saying that Person is of type int and this is not the case, the variable inside is.
You can do something like this to achieve what you want.
var v = new List<Person>() { new Person(1), new Person(2), new Person(3) };
Given that you have a constructor that accepts an int.
Like this one:
public Person(int id)
{
Id = id;
}
Related
I am having some trouble figuring out the right way to go about creating a dynamic query that I can use values from DropDownList controls to filter and sort/order the results of a database query to fill a ListView. I am able to hard code individual queries, which works ok, except for the fact that it takes an incredible amount of effort, and is not easily changed.
My code is as follows (using all filters):
queryResult = From product In myEntities.InventoryProducts
Where product.VendorID = ddlFilterVendor.SelectedValue And product.ItemType = ddlItemType.SelectedValue And product.LabelSize = ddlLabelSize.SelectedValue And product.PrintLabel = boolPrint And product.Edited = boolEdited
Order By product.ID Ascending
Select product
Return queryResult
Is there a better method to this? I would like to be able to select the value from each DropDownList and generate a custom WHERE clause, as well as an ORDER BY clause.
Any help would be greatly appreciated, thanks.
I can give you a simple example as to how to to proceed with your idea. I am sure if you look through StackOverflow or search via google you will get code that does a better job of dynamic expression building. The same concept can be used for order by.
void Main()
{
var ops = new List<Ops>
{
new Ops
{
OperandType = typeof(string),
OpType=OpType.Equals,
OperandName = "Name",
ValueToCompare = "MM" // in your case this will be the values from the dropdowns
},
new Ops
{
OperandType = typeof(int),
OpType=OpType.Equals,
OperandName = "ID",
ValueToCompare = 1
},
};
var testClasses = new List<TestClass>
{
new TestClass { ID =1, Name = "MM", Date = new DateTime(2014,12,1)},
new TestClass { ID =2, Name = "BB", Date = new DateTime(2014,12,2)}
};
// this will produce prop => ((prop.Name == "MM") And (prop.ID == 1))
var whereDelegate = ExpressionBuilder.BuildExpressions<TestClass>(ops);
foreach(var item in testClasses.Where(whereDelegate))
{
Console.WriteLine("ID " +item.ID);
Console.WriteLine("Name " +item.Name);
Console.WriteLine("Date" + item.Date);
}
}
// Define other methods and classes here
public enum OpType
{
Equals
}
public class Ops
{
public Type OperandType {get; set;}
public OpType OpType {get; set;}
public string OperandName {get;set;}
public object ValueToCompare {get;set;}
}
public class TestClass
{
public int ID {get;set;}
public string Name {get; set;}
public DateTime Date {get;set;}
}
public class ExpressionBuilder
{
public static Func<T,bool> BuildExpressions<T>( List<Ops> opList)
{
Expression currentExpression= null;
var parameterExpression = Expression.Parameter(typeof(T), "prop");
for(int i =0; i< opList.Count; i++)
{
var op = opList[i];
Expression innerExpression = null;
switch(op.OpType)
{
case OpType.Equals :
{
var propertyExpression = Expression.Property(parameterExpression ,
op.OperandName);
var constExpression = Expression.Constant(op.ValueToCompare);
innerExpression = Expression.Equal(propertyExpression,
constExpression);
break;
}
}
if (i >0)
{
currentExpression = Expression.And(currentExpression, innerExpression);
}
else
{
currentExpression = innerExpression;
}
}
var lambdaExpression = Expression.Lambda<Func<T,bool>>(currentExpression,
new []{parameterExpression });
Console.WriteLine(lambdaExpression);
return lambdaExpression.Compile() ;
}
}
I want to automate the Setup code by a given array containing expected result and parameters.
Something like data driven setup.
My existing code:
var mock = new Mock<ILogin>();
var testDataTable = new object[,]
{
{ LoginResult.Success, "Jack", "123!##"}
, { LoginResult.WrongPassword, "Jack", "123321"}
, { LoginResult.NoSuchUser, "Peter", "123!##"}
};
// ForEachRow is my own extension method
testDataTable.ForEachRow((row) =>
{
var result = (LoginResult)row[0];
var username = (string)row[1];
var password = (string)row[2];
mock.Setup(o => o.Login(
It.Is<string>(u => u == username),
It.Is<string>(p => p == password)
)).Returns(result);
});
return mock.Object;
Code that I wish:
var mock = new Mock<ILogin>();
new object[,]
{
{ LoginResult.Success, "Jack", "123!##"}
, { LoginResult.WrongPassword, "Jack", "123321"}
, { LoginResult.NoSuchUser, "Peter", "123!##"}
}.ForEachRow((row) =>
{
var exprTree = (ILogin o)=>o.Login("ANY", "ANY");
AutoSetup(mock, exprTree, row); // <---- How to write this AutoSetup?
});
return mock.Object;
How to write the AutoSetup(mock, exprTree, dataArray) function above?
It takes three parameters:
mock: A mock object, e.g. new Mock()
exprTree: Expression tree that represents a method to be setup
dataArray: An object[], the 0 element is the expected result, and others are parameters that passed to the method
This was an interesting challenge. I think I have a working implementation for your AutoSetup method, using the expressions API. If anyone has a simpler solution, I'd love to see it.
static void AutoSetup<TMock, TResult>(Mock<TMock> mock, Expression<Func<TMock, TResult>> exprTree, object[] items) where TMock : class
{
var methodCallExpr = exprTree.Body as MethodCallExpression;
var arguments = items.Skip(1).Select(o => Expression.Constant(o));
var updatedMethod = methodCallExpr.Update(methodCallExpr.Object, arguments);
var updatedLambda = exprTree.Update(updatedMethod, exprTree.Parameters);
mock.Setup(updatedLambda).Returns((TResult)items[0]);
}
Here is a full working test as a console app, with an implementation of ForEachRow, which you didn't provide.
class Program
{
static void Main(string[] args)
{
var login = SetUp();
Console.WriteLine(login.Login("Jack", "123!##"));
Console.WriteLine(login.Login("Jack", "123321"));
Console.WriteLine(login.Login("Peter", "123!##"));
Console.ReadKey();
}
static ILogin SetUp()
{
var mock = new Mock<ILogin>(MockBehavior.Strict);
var rows = new object[,]
{
{ LoginResult.Success, "Jack", "123!##" },
{ LoginResult.WrongPassword, "Jack", "123321" },
{ LoginResult.NoSuchUser, "Peter", "123!##" }
};
rows.ForEachRow((row) => AutoSetup(mock, (ILogin l) => l.Login("ANY", "ANY"), row));
return mock.Object;
}
private static void AutoSetup<TMock, TResult>(Mock<TMock> mock, Expression<Func<TMock, TResult>> exprTree, object[] items) where TMock : class
{
var methodCallExpr = exprTree.Body as MethodCallExpression;
var arguments = items.Skip(1).Select(o => Expression.Constant(o));
var updatedMethod = methodCallExpr.Update(methodCallExpr.Object, arguments);
var updatedLambda = exprTree.Update(updatedMethod, exprTree.Parameters);
mock.Setup(updatedLambda).Returns((TResult)items[0]);
}
}
public static class ArrayExtensions
{
public static void ForEachRow<T>(this T[,] rows, Action<T[]> action)
{
var x = rows.GetLength(1);
var y = rows.GetLength(0);
for (int i = 0; i < y; i++)
{
var row = new T[x];
for (int j = 0; j < x; j++)
{
row[j] = rows[i, j];
}
action(row);
}
}
}
public interface ILogin
{
LoginResult Login(string p1, string p2);
}
public enum LoginResult
{
Success,
WrongPassword,
NoSuchUser
}
EDIT: You asked in a comment about how to take advantage of the variable parameter matching that Moq provides with the It.IsAny<> method. Because what you pass to your Mock.Setup() is an expression tree, it's able to scan the method parameters and implement special behaviour for any that are calls to It.IsAny<>. However, if you use It.IsAny<> in your test data array, by the time we retrieve it from your items array to set in on the expression, it's not a method call but simply the result of the call it It.IsAny<> which is default(T) (see here).
We need some way of specifying in your test data array that the parameter should be any. Then we can check for this special case and generate the correct MethodCallExpression representing a call to It.IsAny<>.
Here are the changes I made to support this:
Add an Any type to use in your test data
public class Any<T>
{
private Any() { }
public static Any<T> Param { get { return new Any<T>(); } }
}
Update the AutoSetup method to handle this special case:
private static void AutoSetup<TMock, TResult>(Mock<TMock> mock, Expression<Func<TMock, TResult>> exprTree, object[] items) where TMock : class
{
var arguments = items.Skip(1).Select(o => {
var type = o.GetType();
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Any<>))
{
var typeParameter = type.GetGenericArguments();
var genericItIsAny = typeof(It).GetMethod("IsAny");
var itIsAny = genericItIsAny.MakeGenericMethod(typeParameter);
return Expression.Call(itIsAny) as Expression;
}
return Expression.Constant(o);
});
var methodCallExpr = exprTree.Body as MethodCallExpression;
var updatedMethod = methodCallExpr.Update(methodCallExpr.Object, arguments);
var updatedLambda = exprTree.Update(updatedMethod, exprTree.Parameters);
mock.Setup(updatedLambda).Returns((TResult)items[0]);
}
In the test data, use the Any type
{ LoginResult.Success, "NoPasswordUser", Any<string>.Param }
Depending on how you're storing your test data, you might need another way of identifying parameters that you want to be variable (specially formatted string?), but in general this should give you an idea about how to create the correct expressions.
I using openxml to create a powerpoint from an web app.I created a ppt with charts and opened ppt in openxml sdk productivity tool and code which was generated with that i modified the chart data which is coming from database,Code for which i created to modify the chart data as
created a class for the code in the sdk,in that CreatePart() i added these links
ChartPart chartPart1 = slidePart1.AddNewPart<ChartPart>("rId3");
GenerateChartPart1Content(chartPart1);
// This is below code added
#if true // Injects the chart part modification process
var chartModifier1 = new ChartPartModifier();
chartModifier1.UpdateSecondChartPart(chartPart1);
#endif
EmbeddedPackagePart embeddedPackagePart1 = chartPart1.AddNewPart<EmbeddedPackagePart>("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "rId2");
GenerateEmbeddedPackagePart1Content(embeddedPackagePart1);
and created a class for ChartPartModifier()
public void UpdateSecondChartPart(ChartPart chartPart)
{
// Searchs SeriesText and its Values to replace them with your dynamic data
var seriesLabels = chartPart.ChartSpace.Descendants<SeriesText>().ToList();
var seriesValues = chartPart.ChartSpace.Descendants<Values>().ToList();
var categoryAxis = chartPart.ChartSpace.Descendants<CategoryAxisData>().ToList();
for (int i = 0; i < this._lineSecCharts.Count; ++i)
{
var yourLine = this._lineSecCharts[i];
var label = seriesLabels[i].Descendants<NumericValue>().FirstOrDefault();
var values = seriesValues[i].Descendants<NumericValue>().ToList();
var categories = categoryAxis[i].Descendants<NumericValue>().ToList();
// Replaces the label of the series
label.Text = yourLine.Label;
// Replaces the values of the series
for (int valIdx = 0; valIdx < values.Count(); ++valIdx)
{
values[valIdx].Text = yourLine.Plots[valIdx].Value.ToString();
categories[valIdx].Text = yourLine.Plots[valIdx].Category;
}
}
}
Like this is there any way to modify the data in the table,If so can any one provide me the solution is much appreciated.
I found answer after a research i'm able to update the table values from database using openxml
the below code which(if condition) added between table appending the rows and graphicdata appending
table1.Append(tableProperties1);
table1.Append(tableGrid1);
table1.Append(tableRow1);
table1.Append(tableRow2);
table1.Append(tableRow3);
table1.Append(tableRow4);
table1.Append(tableRow5);
table1.Append(tableRow6);
table1.Append(tableRow7);
#if true // Injects the table modification process
TableModifier tableModifier = new TableModifier();//Create a class
tableModifier.UpdateTable(table1);//Send the table object of which you wanted to update
#endif
graphicData1.Append(table1);
graphic1.Append(graphicData1);
In class of TableModifier
using DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Packaging;
public class TableModifier
{
public TableModifier()
{
this.SetupDataSource();
}
public void UpdateTable(Table table)
{
var rows = table.Descendants<TableRow>().ToList();
for (int r = 0; r < rows.Count(); ++r)
{
var yourRow = this._rows[r];
var cells = rows[r].Descendants<TableCell>().ToList();
for (int c = 0; c < cells.Count(); ++c)
{
var yourCell = yourRow.Cells[c];
var text = cells[c].Descendants<Text>().FirstOrDefault();
if (text != null)
{
text.Text = yourCell.Value;
}
}
}
}
private void SetupDataSource()
{
this._rows.Add(new Row()
{
Cells = new List<Cell>()
{
new Cell(){ Value = "Products" },
new Cell(){ Value = "2010" },
new Cell(){ Value = "2011" },
new Cell(){ Value = "2012" },
}
});
for (int i = 0; i < 6; ++i)
{
var productName = string.Format("Product {0}", (char)(i + 'A'));
this._rows.Add(new Row()
{
Cells = new List<Cell>()
{
new Cell(){ Value = productName },
new Cell(){ Value = "10%" },
new Cell(){ Value = "20%" },
new Cell(){ Value = "30%" },
}
});
}
}
#region Private Data Structure
private class Row
{
public List<Cell> Cells { get; set; }
}
private class Cell
{
public string Value { get; set; }
}
#endregion
private List<Row> _rows = new List<Row>();
}
LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
public ActionResult PopulateFromDB(string sidx, string sord, int page, int rows)
{
var context = new NerdDinnerEntities();
var jsonData = new
{
total = 1,
page = page,
sord =sord,
records = context.Authors.Count(),
rows = (from n in context.Authors
select new
{ AuthorId = n.AuthorId ,
cell = new string[] { n.AuthorId.ToString(), n.Name.ToString(), n.Location.ToString() }
}).ToList()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
I am writting ToList or Toarray is it not working the error comes :
public ActionResult PopulateFromDB(string sidx, string sord, int page, int rows)
{
var context = new NerdDinnerEntities();
var jsonData = new
{
total = 1,
page = page,
sord =sord,
records = context.Authors.Count(),
rows = (from n in context.Authors
select new
{ AuthorId = n.AuthorId ,
cell = new string[] { n.AuthorId.ToString(), n.Name.ToString(), n.Location.ToString() }
}).ToList()
};
return Json(jsonData,JsonRequestBehavior.AllowGet);
}
From your code I assume your adding a custom property cell for display/storage purposes on the client-side. I would avoid this as your essentially coupling your API call to one particular client. I would suggest you simply return the data required & deal with it at the client-side specifically e.g.
Server
...
select new
{
Id = n.AuthorId,
Name = n.Name,
Location = n.Location
}).ToList();
...
Client
var response = ...
foreach (var author in response)
{
var cell = new string[] { author.Id.ToString(), author.Name, author.Location };
// do something with cell
}
You should try SqlFunctions.StringConvert to convert this, There is no overload for int so you should cast your number to a double or a decimal.
public ActionResult PopulateFromDB(string sidx, string sord, int page, int rows)
{
var context = new NerdDinnerEntities();
var jsonData = new
{
total = 1,
page = page,
sord =sord,
records = context.Authors.Count(),
rows = (from n in context.Authors
select new
{ AuthorId = n.AuthorId ,
cell = new string[] { SqlFunctions.StringConvert((double)n.AuthorId), n.Name, n.Location }
}).ToList()
};
return Json(jsonData,JsonRequestBehavior.AllowGet);
}
You are not using LinqToSql Classes, if you were using that your code should work, but as you mention that you are using LinqToEntity then You should use SqlFunctions.StringConvert to convert to string.
I have written this class-methods for .net 2.0 to create objects from '|'-separated strings and vise-versa.
But the problem is, they are not giving right results in case of Inherted types, i.e. inherited properties are coming last and the sequence of the data supplied in the form of a '|'-separated string is not working.
For example:
class A
{
int ID;
}
class B : A
{
string Name;
}
the string is "1|John". the methods are reading as the name==1 and ID=="John".
Please tell me how to do it.
public class ObjectConverter<T>
{
public static T TextToObject(string text)
{
T obj = Activator.CreateInstance<T>();
string[] data = text.Split('|');
PropertyInfo[] props = typeof(T).GetProperties();
int objectPropertiesLength = props.Length;
int i = 0;
if (data.Length == objectPropertiesLength)
{
for (i = 0; i < objectPropertiesLength; i++)
{
props[i].SetValue(obj, data[i], null);
}
}
return obj;
}
public static string ObjectToText(T obj)
{
StringBuilder sb = new StringBuilder();
Type t = typeof(T);
PropertyInfo[] props = t.GetProperties();
int i = 0;
foreach (PropertyInfo pi in props)
{
object obj2 = props[i++].GetValue(obj, null);
sb.Append(obj2.ToString() + "|");
}
sb = sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
}
I don't think the runtime assures you that when you call getproperties the property info objects will always be in the same order. You will need to do something like get the list of property names sort them and use the same sorting for serialization and deserialization .
There are at least 3 ways to serialize object built into .net is there a reason why you are not using one of those