I need to achieve something like this but I cannot figure how to make it work:
class Program
{
static List<dynamic> myList = new List<dynamic>();
static void Main(string[] args)
{
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test1", Test2 = "test2" });
// I need to pass a dynamic list of expression like:
GenerateGroup<dynamic>(x=>x.Test, x => x.Test2); //groups myList in 2 groups
GenerateGroup<dynamic>(x=>x.Test2); //groups myList in a single group
}
private static void GenerateGroup<T>(params Expression<Func<T, object>>[] properties)
{
//I need to group for the properties passed as parameters
var result= myList.GroupBy(properties);
}
}
I receive compiler errors:
An expression tree may not contain a dynamic operation
This is only an example of a complex application but at the end, I need to use a list of dynamics and I need to group them with a dynamic list of properties. This is because I read data/properties from multiple PDF sources and it's not possible to use static classes.
Is it possible to fix this error or it is a compiler limitation and I need to approach the problem in another way?
UPDATE
I think I've made a step forward thanks to your answers:
class Program
{
static List<dynamic> myList = new List<dynamic>();
static List<Foo> myListFoo = new List<Foo>();
static void Main(string[] args)
{
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test1", Test2 = "test2" });
myListFoo.Add(new Foo { MyProperty =1});
GenerateGroup<dynamic>(x =>new { x.Test, x.Test2});
GenerateGroup<Foo>(x=>x.MyProperty);
}
private static void GenerateGroup<T>(Func<T, object> properties)
{
var result= myList.GroupBy(properties);
result = myListFoo.GroupBy(properties);
}
}
public class Foo
{
public int MyProperty { get; set; }
}
and I have only a compilation error on groupBy:
'List<dynamic>' does not contain a definition for 'GroupBy' and the best extension method overload 'ParallelEnumerable.GroupBy<T, object>(ParallelQuery<T>, Func<T, object>)' requires a receiver of type 'ParallelQuery<T>'
You need to make some changes to your code:
Expression<Func<,>> is not what you are looking for, the Where overloads accepted by IEnumerable<T> all use Func<,>
There's no reason to make GenerateGroup generic if you are going to hard-code dynamic
Instead of passing multiple parameters, you should create an object that includes the data you want to group by
If you mix all those points, you should end up with something like this:
static void Main(string[] args)
{
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test", Test2 = "test2" });
myList.Add(new { Test = "test1", Test2 = "test2" });
// I need to pass a dynamic list of expression like:
GenerateGroup(x => new { x.Test, x.Test2 } ); //groups myList by Test and Test2
GenerateGroup(x => x.Test2); //groups myList in a single group
}
private static void GenerateGroup(Func<dynamic, object> groupper)
{
var groupped = myList.GroupBy(groupper);
}
Related
So, I am kind of used to structuring things like JavaScript and in light of that I do struggle in some areas in C#. Right now I'm trying to use structures in a way I can call a value using a variable that would match the value I'm going for.
For example my structure would be this:
public struct test
{
public int[] valuesOne;
public int[] valuesTwo;
public test(int[] data)
{
valuesOne = new int[2] { data[0], data[1] };
valuesTwo = new int[2] { data[2], data[3] };
}
}
Okay so say I have all of this and I want to get test.valuesOne[0] but from a variable like so:
string getValue = "valuesOne";
Console.Log(test[getValue][0]);
I know this provides a indexing error, but I'm in a situation where I kind of want this functionality. Sure I can pass my structure through a simple method, but if I can do it in a similar way to this without a huge problem I'd like to.
c# and JavaScript are two different pairs of shoes.
I try to do something similar as your code, however not sure if that's what you're looking for.
class Program
{
static void Main(string[] args)
{
var t = new Test(new int[] { 1, 2, 3, 4 });
var value = t["valueOne"][0];
Console.WriteLine(value);
}
}
public class Test
{
private Dictionary<string, int[]> _data = new Dictionary<string, int[]>();
public Test(int[] data)
{
_data.Add("valueOne", new int[] { data[0], data[1]});
_data.Add("valueTwo", new int[] { data[2], data[3]});
}
public int[] this [string value]
{
get { return _data[value]; }
}
}
you can use dynamic + reflection + this[string key] to do it. but it needs some extra code.
note :
it's a bad idea,this will lose the advantage of strong type checking.
demo :
void Main()
{
var test = new test(new[] {1,2,3,4,5});
Console.WriteLine( test["valuesOne"][0] ); //1
Console.WriteLine( test["valuesTwo"][1] ); //4
}
public struct test
{
public int[] valuesOne;
public int[] valuesTwo;
public test(int[] data)
{
valuesOne = new int[2] { data[0], data[1] };
valuesTwo = new int[2] { data[2], data[3] };
}
public dynamic this[string key]
{
get
{
return this.GetFieldValue(key);
}
}
}
public static class Extension
{
public static object GetFieldValue(this object t, string fieldName)
{
var type = t.GetType();
var fields = type.GetFields();
var field = fields.Single(pi => pi.Name == fieldName);
return field.GetValue(t);
}
}
online demo link : can-you-get-a-value-in-a-structure-through-an-outside-variable-in-c | .NET Fiddle
Usually I too would recommend using a Dictionary as in #gsharp's answer. But since that isn't an option for you, perhaps you could go with a Dictionary of delegates instead:
var accessor = new Dictionary<string, Func<test, int[]>>
{
{ nameof(test.valuesOne), x => x.valuesOne },
{ nameof(test.valuesTwo), x => x.valuesTwo }
};
Now you can access your data like so:
string getValue = "valuesOne";
Console.Log(accessor[getValue](test_instance)[0]);
You can extend this concept by wrapping this Dictionary into an Extension Method:
public static class Extensions
{
private static new Dictionary<string, Func<test, int[]>> accessor =
new Dictionary<string, Func<test, int[]>>
{
{ nameof(test.valuesOne), x => x.valuesOne },
{ nameof(test.valuesTwo), x => x.valuesTwo }
};
public static int[] Property(this test t, string name)
{
return accessor[name](t);
}
}
Then you can write:
Console.Log(test_instance.Property(getValue)[0]);
I have a Simple POCO like this:
[JsonObject(NamingStrategyType = typeof (CamelCaseNamingStrategy))]
public class MyType
{
public string Id { get; set; }
public string Name;
[JsonExtensionData(ReadData = true, WriteData = true)]
public IDictionary<string, object> TypeDetails { get; set; }
}
and a method that gives me a list of MyType
i'm trying to return a list of Dictionary<string,object> with all the TypeDetails of the object list i got.
like this:
types.Select((myType) => myType.TypeDetails)
however, when i run this, what i get is a list of Dictionaries, but with the following shape:
[
{TypeDetails: {the dictionary i want},
{TypeDetails: {the dictionary i want}},
(...)
]
what i was expecting:
[
{the dictionary i want},
{the dictionary i want},
(...)
]
to clarify: i'd like this to be true:
types[0].TypeDetails.equals(r[0])
It's the same as if i were doing
types.Select((myType) => new {myType.TypeDetails})
if i get any other property the select behaves as i expected it.
i can't find any doc that indicates whether dictionaries get a special treatment, nor any other clue about why this is happening.
Use .SelectMany() on the Dictionary's values, like so:
types.SelectMany((myType) => myType.TypeDetails.Values)
Either your return expectation/description is out:
i'm trying to return a list of Dictionary<string,Object>
or, (assuming (myType) is of type MyType), your real code does not match:
types.Select((myType) => myType.TypeDetails)
The example code below does return a collection of Dictionary<string,Object>, it'd be interesting to see where your code differs from it:
var data = new[]
{
new MyType()
{
TypeDetails = new Dictionary<string, object>() { { "foo", "bar" } }
},
new MyType()
{
TypeDetails = new Dictionary<string, object>() { { "baz", "qux" } }
},
};
var r = data.Select(d => d.TypeDetails);
I'm pretty new to xUnit and here's what I'd like to achieve:
[Theory]
[InlineData((Config y) => y.Param1)]
[InlineData((Config y) => y.Param2)]
public void HasConfiguration(Func<Config, string> item)
{
var configuration = serviceProvider.GetService<GenericConfig>();
var x = item(configuration.Config1); // Config1 is of type Config
Assert.True(!string.IsNullOrEmpty(x));
}
Basically, I have a GenericConfig object which contains Config and other kind of configurations, but I need to check that every single parameter is valid. Since they're all string, I wanted to simplify using [InlineData] attribute instead of writing N equals tests.
Unfortunately the error I'm getting is "Cannot convert lambda expression to type 'object[]' because it's not a delegate type", which is pretty much clear.
Do you have any idea on how to overcome this?
In addition to the already posted answers. The test cases can be simplified by directly yielding the lambdas.
public class ConfigTestDataProvider
{
public static IEnumerable<object[]> TestCases
{
get
{
yield return new object [] { (Func<Config, object>)((x) => x.Param1) };
yield return new object [] { (Func<Config, object>)((x) => x.Param2) };
}
}
}
This test ConfigTestDataProvider can then directly inject the lambdas.
[Theory]
[MemberData(nameof(ConfigTestCase.TestCases), MemberType = typeof(ConfigTestCase))]
public void Test(Func<Config, object> func)
{
var config = serviceProvider.GetService<GenericConfig>();
var result = func(config.Config1);
Assert.True(!string.IsNullOrEmpty(result));
}
Actually, I was able to find a solution which is a bit better than the one provided by Iqon (thank you!).
Apparently, the InlineData attribute only supports primitive data types. If you need more complex types, you can use the MemberData attribute to feed the unit test with data from a custom data provider.
Here's how I solved the problem:
public class ConfigTestCase
{
public static readonly IReadOnlyDictionary<string, Func<Config, string>> testCases = new Dictionary<string, Func<Config, string>>
{
{ nameof(Config.Param1), (Config x) => x.Param1 },
{ nameof(Config.Param2), (Config x) => x.Param2 }
}
.ToImmutableDictionary();
public static IEnumerable<object[]> TestCases
{
get
{
var items = new List<object[]>();
foreach (var item in testCases)
items.Add(new object[] { item.Key });
return items;
}
}
}
And here's the test method:
[Theory]
[MemberData(nameof(ConfigTestCase.TestCases), MemberType = typeof(ConfigTestCase))]
public void Test(string currentField)
{
var func = ConfigTestCase.testCases.FirstOrDefault(x => x.Key == currentField).Value;
var config = serviceProvider.GetService<GenericConfig>();
var result = func(config.Config1);
Assert.True(!string.IsNullOrEmpty(result));
}
I could maybe come up with something a bit better or cleaner, but for now it works and the code is not duplicated.
I have the problem the same to you, and I found the solution that using TheoryData class and MemberData attribute. Here is the example and I hope the code usefully:
public class FooServiceTest
{
private IFooService _fooService;
private Mock<IFooRepository> _fooRepository;
//dummy data expression
//first parameter is expression
//second parameter is expected
public static TheoryData<Expression<Func<Foo, bool>>, object> dataExpression = new TheoryData<Expression<Func<Foo, bool>>, object>()
{
{ (p) => p.FooName == "Helios", "Helios" },
{ (p) => p.FooDescription == "Helios" && p.FooId == 1, "Helios" },
{ (p) => p.FooId == 2, "Poseidon" },
};
//dummy data source
public static List<Foo> DataTest = new List<Foo>
{
new Foo() { FooId = 1, FooName = "Helios", FooDescription = "Helios Description" },
new Foo() { FooId = 2, FooName = "Poseidon", FooDescription = "Poseidon Description" },
};
//constructor
public FooServiceTest()
{
this._fooRepository = new Mock<IFooRepository>();
this._fooService = new FooService(this._fooRepository.Object);
}
[Theory]
[MemberData(nameof(dataExpression))]
public void Find_Test(Expression<Func<Foo, bool>> expression, object expected)
{
this._fooRepository.Setup(setup => setup.FindAsync(It.IsAny<Expression<Func<Foo, bool>>>()))
.ReturnsAsync(DataTest.Where(expression.Compile()));
var actual = this._fooService.FindAsync(expression).Result;
Assert.Equal(expected, actual.FooName);
}
}
Oddly delegates are not objects, but Actions or Funcs are. To do this, you have to cast the lambda to one of these types.
object o = (Func<Config, string>)((Config y) => y.Param1)
But doing this, your expression is not constant anymore. So this will prevent usage in an Attribute.
There is no way of passing lambdas as attributes.
One possible solution would be to use function calls, instead of attributes. Not as pretty, but could solve your problem without duplicate code:
private void HasConfiguration(Func<Config, string> item)
{
var configuration = serviceProvider.GetService<GenericConfig>();
var x = item(configuration.Config1); // Config1 is of type Config
Assert.True(!string.IsNullOrEmpty(x));
}
[Theory]
public Test1()
{
HasConfiguration((Config y) => y.Param1);
}
[Theory]
public Test2()
{
HasConfiguration((Config y) => y.Param2);
}
public class HrcpDbTests
{
[Theory]
[MemberData(nameof(TestData))]
public void Test(Expression<Func<bool>> exp)
{
// Arrange
// Act
// Assert
}
public static IEnumerable<object[]> TestData
{
get
{
Expression<Func<bool>> mockExp1 = () => 1 == 0;
Expression<Func<bool>> mockExp2 = () => 1 != 2;
return new List<object[]>
{
new object[]
{
mockExp1
},
new object[]
{
mockExp2
}
}
}
}
}
Consider the following class deriving from List:
public class Foo : List<string>
{
public string Bar { get; set; }
}
Serializing it with JSON.NET dumps the Bar property and produces a regular array:
var foo = new Foo() { "a", "b", "c" };
foo.Bar = "baz";
JsonConvert.SerializeObject(foo); // ["a","b","c"]
What can I do to obtain the following array-like object as the result of my serialization?
{"0": "a", "1": "b", "2": "c", "length": 3, "bar": "baz"}
Is a custom serializer the only way to go or is there a JSON.NET setting that can do this for me?
I think the easiest way to get what you are looking for, is to do something like this:
var foo = new Foo() { "a", "b", "c" };
foo.Bar = "baz";
var data = foo
.Select((value, index) => new { value, index })
.ToDictionary(wrapper => wrapper.index.ToString(), wrapper => (object)wrapper.value);
data.Add("length", foo.Count);
data.Add("bar", foo.Bar);
var json = JsonConvert.SerializeObject(data);
//{"0":"a","1":"b","2":"c","length":3,"bar":"baz"}
A more generic way to solve this problem for all elements with any amount of properties would be this Code:
var foo = new Foo() { "a", "b", "c" };
foo.Bar = "baz";
foo.Beer = "beer";
var json = GetJsonWithItemsAndProperties(foo);
//{"0":"a","1":"b","2":"c","length":3,"Bar":"baz","Beer":"beer"}
//...//
private static string GetJsonWithItemsAndProperties<T>(IReadOnlyCollection<T> listWithProperties)
{
var data = listWithProperties
.Select((value, index) => new {value, index})
.ToDictionary(wrapper => wrapper.index.ToString(), wrapper => (object) wrapper.value);
data.Add("length", data.Count);
listWithProperties.GetType()
.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.DeclaredOnly).ToList()
.ForEach(p => data.Add(p.Name, p.GetValue(listWithProperties)));
return JsonConvert.SerializeObject(data);
}
Expected code in C# (that Java has)
List<String> myList = new List<String>() {{
add("Hello");
add("World!");
}}
// myList = [ "Hello", "World" ]
Just wondering if there is an equivalent, possibly with C#'s static constructors?
EDIT:
To clarify this isn't explicitly for Collections but for any class structure.
For example:
abstract class myClass {
String data;
List<String> list;
void setupList() {
list = new List<String>();
}
}
...
var obj = new myClass() {{
data = "Yo";
setupList();
}};
You're looking for the collection initializer syntax:
List<String> myList = new List<String>() {"Hello","World!"};
This is an object initializer that also uses collection initializers (note the type inference in the collection initializers, the List that is created is of type List) :
var myClass = new MyClass{
Data = "foo",
List = new List{"item1", "item2"},
IntArray = new[]{1,2,3},
Dictionary = new Dictionary<string,string>{{"key1","value1"},{"key2","value2"}},
};
You can't call arbitrary methods like SetupList() in an initializer, instead you would initialize the List property the first time it is accessed or statically, etc.
You can use the Lazy class or implement it yourself like so (?? is the null coalescing operator):
class MyClass{
public string Data { get; set; }
private IList<string> _list0 = new List();
public IList<string> List0
{
get
{
return _list0;
}
}
private IList<string> _list1;
public IList<string> List1
{
get
{
return _list1 ?? (_list1 = new List());
}
}
private readonly Lazy<IList<string>> _lazyList = new Lazy<IList<string>>(() => new List<string>());
public IList<string> List2
{
get
{
return _lazyList.Value;
}
}
}
This is how you can add items to a list of strings
List<string> myList = new List<string>();
myList.Add("Hello");
myList.Add("World!");
And if you want to remove them you can simply do this
myList.Remove("Hello");
myList.Remove("World!");