I am new to C# and I am trying to create a method that accept generic parameter type like in Javascript.
Let says I have a List of User
objects with name
and id
properties.
In Javascript , to search through the list using property value will be as simple as:
class User{
constructor(name, id){
this.name = name;
this.id = id;
}
}
let users = [
new User("John",1),
new User("Deer", 2),
new User("Bruce", 3),
]
function findArr(arr, propertyName, propertyValue){
for(let a of arr)
if(a[propertyName] === propertyValue)
return a;
return null;
}
console.log(findArr(users, "name", "Deer"))
console.log(findArr(users, "id", 3))
Then, I try to recreate this in C#:
using System;
using System.Collections.Generic;
using System.Linq;
public class User{
public string name {get; set;}
public int id {get; set;}
}
public class HelloWorld
{
public static void Main(string[] args)
{
List<User> Users = new List<User>{
new User{name="John", id=1},
new User{name="Deer", id=2},
new User{name="Bruce", id=3}
};
int propertyValue = 2;
var u = FindList<User, int>(Users, "id", ref propertyValue);
Console.WriteLine(u.name " " u.id);
}
public static T FindList<T, K>(List<T> obj, string propertyName, ref K propertyValue){
return (T)obj.FirstOrDefault(o=>
(K)o.GetType().GetProperty(propertyName).GetValue(o, null)
==
propertyValue
);
}
}
But this will throw exception: Cannot use ref, out, or in parameter 'propertyValue' inside an anonymous method, lambda expression, query expression, or local function
.
Why is this exception thrown?
How do I make this work?
CodePudding user response:
As the error message states, you cannot use the ref or out keywords in an anonymous function. This is by design, as detailed in this answer.
The good news is, you do not need to use ref at all. You can achieve what you want simply by passing the property value as a normal parameter, like so:
public static T FindList<T, K>(List<T> obj, string propertyName, K propertyValue){
return (T)obj.FirstOrDefault(o=>
EqualityComparer<K>.Default.Equals((K)o.GetType().GetProperty(propertyName).GetValue(o, null) , propertyValue));
}
Note that the equality check with == operator won't work for unconstrained generic type in general, so we use the EqualityComparer method instead.
CodePudding user response:
Javascript is a weakly typed language, every object is essentially just a dictionary.
If you ever find yourself accessing properties by name in C#, you're probably doing something "wrong".
Rather than using reflection, you could pass in a function to access the property;
public static T FindList<T, V>(List<T> obj, Func<T,V> propertyAccess, V propertyValue){
return obj.FirstOrDefault(o => propertyAccess(o) == propertyValue);
}
var u = FindList<User, int>(Users, u => u.id, propertyValue);
However, I don't think this method really adds anything to your C# code. You'd be better off just writing the straight forward solution, without complicating anything with your own "helper" method;
var u = Users.FirstOrDefault(u => u.id == propertyValue);
It's not the same as the javascript code you are familiar with. But you're writing in C# now. If you want to work with other C# programmers, you will need to change the way you think about programming problems.