I was digging into MVC 4 WebGrid's code, and i see it's used as this
grid.Column("Id", format: (item) => item.GetSelectLink(item.Id)),
I wasn't sure what the "item" parameter is, so I looked into the source code, and it seems like it's a "WebGridRow" class. The issue for me is, above code is looking for an ".Id" property, but it doesn't exist in the class. The only property that is anywhere close to it looks like the follwing
public object this[string name]
{
get
{
if (String.IsNullOrEmpty(name))
{
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "name");
}
object value = null;
if (!TryGetMember(name, out value))
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
HelpersResources.WebGrid_ColumnNotFound, name));
}
return value;
}
}
I have never seen a property defined like "this[string name]", what does it mean? dynamic property?
I tried to search on the web, but not sure what to search for, I couldn't come up with any results / explanation for it.
Please help. Thanks
I think there's two consents here you don't understand (or I simply don't understand your question).
this[..] properties are index-properties. They are used like array-expressions. For instance, you could imagine creating your own "array" like this:
public class MyArray {
string[] _storrage = new string[100];
public string this[int index] {
get { return _storrage[index]; }
set { _storrage[index] = value; }
}
}
You can create index-properties with multiple arguments as well, and they can be overloaded. For instance, some lists allows you to access items either by name (this[string name]) and index (this[int index]). In all actuality it's just syntactic sugar so you don't have to write methods like getItem(int index) as you do in java.
The other consept that it seems you're not understanding (though not apparent from your question) is lambda-methods. In your code:
(item) => item.GetSelectLink(item.Id)
is a lambda-method. For instance if the method Colum on your grid-object has the following signature:
public void Column<T>(string name, Func<T, string>)
the expression (item) => item.GetSelectLink(item.Id) would evaluate to a method that takes a T and returns a string. An alternative way to create the same functionality is to do this:
// in class
public string GetIdField(YourClassType item) { return item.GetSelectLink(item.Id); }
// in Column-call
grid.Column("Id", format: GetIdField);
You can read more about lambdas here: http://msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx
[Edit]
To show a quick example of a lambda that might shred some light on this:
var list = new List<string>() { "a", "b", "c" };
list.ForEach((item) => Console.WriteLine(item));
this will output "a", "b" and "c" (see it run at http://ideone.com/MGZxfr).
The equivalent (without using a lambda) would be something like this:
void Main() {
var list = new List<string>() { "a", "b", "c" };
foreach(var item in list) Print(item);
}
void Print(string item) { Console.WriteLine(item); }
It's not exactly a property, but a [] operator.
the get method will be called when you will do something like this:
var a = Ob["hello"]
and the set:
ob["hello"] = 5
It is an indexer, MSDN has you covered
This is called an indexer
You can create your own indexer property as well.
It is commonly used in collections such as Array, List or Dictionary.
http://msdn.microsoft.com/en-us/library/vstudio/6x16t2tx.aspx
Related
There is a method that accepts 2 parameters:
int selectedClass;
int selectedFunction;
Next, there goes 2 switch statements. First of all, it determines child class type using enum:
ParentClass p;
switch(selectedClass){
case (int)ClassTypes.A:
p = new classA();
break;
case (int)ClassTypes.B:
p = new classB();
break;
case (int)ClassTypes.C:
p = new classC();
break;
}
And it goes on an on for like 50 more statements. Furthermore, there is another switch statement that determines a function:
string result;
switch(selectedFunction){
case (int)FunctionTypes.Func1:
result = p.function1();
break;
case (int)FunctionTypes.Func2:
result = p.function2();
break;
case (int)FunctionTypes.Func3:
result = p.function3();
break;
}
I did use the search, there are a lot of examples of improving the second switch statement, but not the first one. The 1st question is: how do we determine both child class and function with no switch statements?
2nd: In js I would do something like that:
functionsArray[selectedClass][selectedFunction]();
Is it possible to implement similar kind of mapping in c#?
Update #1:
I have replaced the 1st switch with the following code:
public static Dictionary<ClassTypes, Type> typeDict = new Dictionary<ClassTypes, Type>()
{
{ ClassTypes.A , typeof(classA) },
{ ClassTypes.B , typeof(classB) },
{ ClassTypes.C , typeof(classC) }
};
ParentClass p = (ParentClass)Activator.CreateInstance(typeDict[selectedClass]);
I can't say I understand the logic that lead you to pick this strange design, but I can think of at least two ways to improve it, providing all the functions you are calling are implemented in the base class (and overriden when needed in the derived classes, of course).
Both solutions are only relevant in case all classes provides a parameter-less constructor and parameter-less functions, and executing the functions does not require further initialization:
The first solution would require you to change the method signature, and force the calling method to know the types of the classes so you might not be able to implement it but it involves far less code.
ExecuteMethod<TClass>(Func<TClass, string> func) where T: BaseClass, new()
(
return func(new T());
)
And you call it like this:
var result = ExecuteMethod<ClassA>(a => a.Function1);
The second solution
This might be more suitable for your needs:
You will need to create two dictionaries and populate them, like this:
private Dictionary<int, Func<ParentClass>> constructors = new Dictionary<int, Func<ParentClass>>()
{
{1, () => new ClassA()},
{2, () => new ClassB()}
// more of the same
};
private Dictionary<int, Func<ParentClass, string>> methods = new Dictionary<int, Func<ParentClass, string>>()
{
{1, i => i.function1},
{2, i => i.function2}
// more of the same
};
Then your method can still take two ints and return a string:
string DoSomething(int classType, int function)
{
var instance = constructors[classType].Invoke();
return methods[function].Invoke(instance);
}
Please note that the code is written directly here and not tested, so I might have missed a thing or two, but this is the general idea.
I did some changes to your original code, I changed the input parameters to strings, assuming you can directly take names as input. And then instantiating using the first method and invoking using the second. I have added an overload if you want to continue to use the Enum.
string selectedClass;
string selectedFunction;
public object GetClassInstanceFromName(string name)
{
object type = Type.GetType($"{this.GetType().Namespace}.{name}";
return Activator.CreateInstance((Type)type);
}
public string InVokefunctionByName(object instance,string methName)
{
return instance.GetType().GetMethod(methName).Invoke(instance, null) as string;
}
//Overload if you want to continue to use your enum
public object GetClassInstanceFromName(ClassTypes name)
{
return
Activator.CreateInstance(Assembly.GetExecutingAssembly().FullName,
"class" +name.ToString());
}
private void Test()
{
object a = GetClassInstanceFromName(selectedClass);
Console.WriteLine(InVokefunctionByName(a, selectedFunction));
Console.ReadKey();
}
Also switching to a better design will always be recommended way.
Is there a simpler way to write the following? I.E., without the lambda.
var strings = new[] { "Alabama", "Mississippi", "Louisiana" };
var ordered = strings.OrderBy(x => x);
Seems like it should be possible, since string implements IEquatable<string>.
It's IComparable that matters more thanIEquatable here, but it is possible:
Array.Sort(strings);
This works because strings is already an array. Since you asked for any IEnumerable:
var ary = strings.ToArray();
Array.Sort(ary);
Note the extra variable is also important in this second sample, because Array.Sort() sorts the actual object passed without returning the results, and calling .ToArray() created a new array that was then thrown away. Without the extra variable, you lose your work.
There is a similar sort method on the List<T> object you can use, as well.
You can also make your own extension method for this:
public static class MyExtensions
{
public static IOrderedEnumerable<T> Sort(this IEnumerable<T> items) where T : IComparable
{
return items.OrderBy(i => i);
}
}
And now you could just say:
var ordered = strings.Sort();
For .NET 7 or higher, use Order.
var strings = new[] { "Alabama", "Mississippi", "Louisiana" };
var ordered = strings.Order();
dotnet/runtime#67194
I have code that looks something like this:
var selectedItems = ItemList.SelectedItems().ToList();
var selectedItems2 = ItemList2.SelectedItems().ToList();
selectedItems[0] = selectedItems2[0];
Here's a look at the SelectedItems extension method:
public static IEnumerable<T> SelectedItems<T>(this IEnumerable<T> source) where T : ISelectable
{
return source.Where(s => s.IsSelected);
}
Whenever I do a ReferenceEquals(ItemList, selectedItems), the value returns false and whenever I modify a value within any of the lists, the changes aren't reflected in the other list.
The Items in the ItemList are reference types (custom made classes).
What am I doing wrong?
EDIT:
Here's the original code. I didn't want to overcomplicate things but here it is nonetheless:
var test = Map.TileMap.Layers[0].TileList.SelectedItems().ToList();
if (ReferenceEquals(test[0], Map.TileMap.Layers[0].TileList[0]))
{
// returns true
}
var tileset2D = Tileset.TileMap.Layers[0].TileList.SelectedItems().To2D(t => t.SelectableRegion.Y).ToList();
test[0] = tileset2D[0][0];
// test[0] has changed but Tileset.TileMap.Layers[0].TileList[0] hasn't changed.
Here's the To2D extension method:
public static IEnumerable<IEnumerable<T>> To2D<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source), "Source collection cannot be null");
}
return source.GroupBy(keySelector);
}
Calling .ToList() isn't a casting operation. It generates a brand new list object and populates it with the results of the enumerable prior to .ToList(). The references aren't the same because they are different lists.
The SelectedItems method should be returning instances of the original list. So you should be able to test that it works.
With this sample code:
var ItemList = new List<Selectable>()
{
new Selectable() { IsSelected = true },
new Selectable() { IsSelected = false },
};
var selectedItems = ItemList.SelectedItems().ToList();
Console.WriteLine(selectedItems[0].IsSelected);
ItemList[0].IsSelected = false;
Console.WriteLine(selectedItems[0].IsSelected);
I get the results:
True
False
My implementation of Selectable is:
public class Selectable : ISelectable
{
public bool IsSelected { get; set; }
}
You must have something happening in code you haven't shown.
You've added some more code, and now the snippit .GroupBy(t => t.SelectableRegion.Y) makes me think that the grouping isn't working as expected. You should test your assumptions about what the grouping key returns
My suggestion, at this point, is that you avoid recreating extension methods. It would be better to write source.Where(s => s.IsSelected).GroupBy(t => t.SelectableRegion.Y) than source.SelectedItems().To2D(t => t.SelectableRegion.Y). This kind of thing just confuses the code and makes it harder to reason about. The kinds of errors you're experience surface far too often.
The problem was that I was assigning a new reference to my list item
test[0] = tileset2D[0][0];
So now test[0] is point to the same address in memory as tileset2D[0][0]. That's why the values in test[0] weren't modifying values inside Map.TileMap.Layers[0].TileList.
So I basically have to create some time of DeepClone method that will copy the values and clone the references without assigning a new reference to my TileList item.
Thanks for all the help :)
If I want an empty enumeration, I can call Enumerable.Empty<T>(). But what if I want to convert a scalar type to an enumeration?
Normally I'd write new List<string> {myString} to pass myString to a function that accepts IEnumerable<string>. Is there a more LINQ-y way?
You can use Repeat:
var justOne = Enumerable.Repeat(value, 1);
Or just an array of course:
var singleElementArray = new[] { value };
The array version is mutable of course, whereas Enumerable.Repeat isn't.
Perhaps the shortest form is
var sequence = new[] { value };
There is, but it's less efficient than using a List or Array:
// an enumeration containing only the number 13.
var oneIntEnumeration = Enumerable.Repeat(13, 1);
You can also write your own extension method:
public static class Extensions
{
public static IEnumerable<T> AsEnumerable<T>(this T item)
{
yield return item;
}
}
Now I haven't done that, and now that I know about Enumerable.Repeat, I probably never will (learn something new every day). But I have done this:
public static IEnumerable<T> MakeEnumerable<T>(params T[] items)
{
return items;
}
And this, of course, works if you call it with a single argument. But maybe there's something like this in the framework already, that I haven't discovered yet.
I have a lot of functions that look like this. Each has N arguments and each creates an SQLparamater array with each paramater being of this very similar form.
[WebMethod]
public static string accessServer(string dataField1, string dataField2, string dataField3) {
string value;
SQLParamater[] param = new SQLParameter[len] // len is the amount of arguments
param[0] = new SQLParameter("#dataField1", dataField1);
param[1] = new SQLParameter("#dataField2", dataField2);
param[2] = new SQLParameter("#dataField3", dataField3);
...
// do something with param
return value;
}
This looks like it can be done generically using a combination of Reflection and accessing the paramaters in a generic way.
Ideally a method of the form
public static SQLParamater[] getParams(someType paramaters)
and SQLParamater[] param = getParams(...)
I'm not sure how to pass on all the paramaters generically.
[Edit]
Note that the names of these datafields are important. It's not just an array of strings but rather a set of key/value pairs.
[/Edit]
You can use a function with variable arguments: name(params string[] arguments), so you can call, for example: name(arg1,arg2,arg3,arg4);
This has been asked about before (can't find that question though), the problem however is that while you can figure out the parameter names by using reflection MethodBase.GetCurrentMethod() you can't zip those names together with the parameter values because there's no way for you to access a parameter list of values.
There are other ways of trying to work around this very specific tiresome problem but I don't recommend doing it this way, it just doesn't make a lot of sense.
Now, given a method like this:
static void SomeMethod(string arg1, int arg2, object arg3)
{
}
You could do this:
static void Main()
{
var b = 123;
// this now becomes necessary as it's the only way of getting at the metadata
// in a presumable safe manner
Expression<Action> x = () => SomeMethod("a", b, "a" + b);
var args = GetArgs(x);
foreach (var item in args)
{
Console.WriteLine("{0}: {1}", item.Key, item.Value);
}
}
And implement the GetArgs method like so (you still need a way of putting those values somewhere becuase the invocation never occurs):
static IDictionary<string, object> GetArgs(Expression<Action> x)
{
var args = new Dictionary<string, object>();
var m = (MethodCallExpression)x.Body;
var parameters = m.Method.GetParameters();
for (int i = 0; i < m.Arguments.Count; i++)
{
// an easy way of getting at the value,
// no matter the complexity of the expression
args[parameters[i].Name] = Expression
.Lambda(m.Arguments[i])
.Compile()
.DynamicInvoke();
}
return args;
}
You infer the collection of name/value pairs from the expression tree created by the compiler, it's doable but kind of odd.
I think your API design is flawed if you need this, you would better have one method, which accepts a collection of some sort.
Code duplication like this is almost never the correct way to get things done.
EDIT
On topic:
I guess you can get the values from the stack: http://www.thescarms.com/dotnet/StackFrame.aspx
we do it like this:
var dict=new Dictionary
{
{"#param1",value1},
{"#param2",value2},
{"#param3",value3},
{"#param4",value4},
....
};
DALayer.ExecuteProc("procName",dict);
In the ExecuteProc function you can iterate over Dictionary object and set params using KeyValuePair object. But if you have to setup the datatype, lengths etc for the parameters then you have to do more work like preparing the sql command to query about parameters or passing more complicated object as parameter that contains information about datatype, length and direction etc.