I am wondering if there is an alternative to dot notation in C#. For instance, in Javascript, I can have an object like this:
const myObj = { foo: "bar" }
And then I can reference it like this:
let x = "foo";
let y = myObj[x]; //sets y = "bar"
Is this possible in C#? I have not found anything of the sort, but am wondering if there are alternatives that would function similarly.
You can implement an indexer in your class:
public class A
{
public int X { get; set; }
public string Y { get; set; }
public object this[string name]
{
get => GetType().GetProperty(name).GetValue(this, null);
set => GetType().GetProperty(name).SetValue(this, value);
}
}
Then use it:
var a = new A();
a["X"] = 10;
a["Y"] = "abc";
Console.WriteLine(a.X);
Console.WriteLine(a.Y);
You can have something similar using dynamic but you have to explicitly get the dictionary interface to use the array syntax.
dynamic myObject = new ExpandoObject();
myObject.greeting = "hello";
IDictionary<string, object> myDict = myObject;
Console.WriteLine(myDict["greeting"]);
Note that it works in both directions. You can add that after the previous code:
myDict["name"] = "Joe";
Console.WriteLine(myObject.name);
You can have both syntax if you don't mind having an intermediate object like myObject.something.name.
The code would look like:
void Main()
{
BothSyntax test= new BothSyntax();
test.dyn.greeting = "Hi";
Console.WriteLine(test["greeting"]);
test["name"] = "Joe";
Console.WriteLine(test.dyn.name);
}
class BothSyntax
{
public dynamic dyn => eo;
private ExpandoObject eo = new ExpandoObject();
public object this[string key]
{
get
{
return ((IDictionary<string, object>)eo)[key];
}
set
{
((IDictionary<string, object>)eo)[key] = value;
}
}
}
Related
I am trying to implement a generic container that can be indexed both ways:
class DoubleIndexer<T1, T2>
{
public T2 this[T1 key] { get => default; set { } }
public T1 this[T2 key] { get => default; set { } }
}
The problem is that I get compile-time errors when I try to use an instance with the same type for T1 and T2:
var int_int = new DoubleIndexer<int, int>();
int_int[1] = 13; // CS0121: The call is ambiguous between the following
// methods or properties: 'DoubleIndexer<T1, T2>.this[T1]'
// and 'DoubleIndexer<T1, T2>.this[T2]'
There is no problem when the types T1 and T2 are different:
var int_string = new DoubleIndexer<int, string>();
int_string[1] = "Hello"; // OK
int_string["Hello"] = 1; // OK
var int_byte = new DoubleIndexer<int, byte>();
int_byte[1] = 13; // OK
int_byte[(byte)13] = 1; // OK
Is there any workaround for this problem, or I am forced to change the interface of my generic class?
Coders are used to Dictionary<int, string> which works in one direction Key > Value. Given the language limitation, you should go with an approach that is more intuitive, predictable, and fits in with prior art.
Sub-interface only for the reversed situation
Code:
var lookupByIDReversible = new DoubleIndexer<int, string>();
...
lookupByIDReversible[1] = "hello";
lookupByIDReversible.Reverse["hello"] = 1;
You might think of some better language.
I'll leave the implementation up to you.
RecordSet-centric with Nx indexers possible
Another approach entirely, would make use of a recordset pattern that can emit indexers that remain linked to the set. The set is the hub for all indexers.
class Message
{
public int ID;
public int ToUserID;
public int FromUserID
public string MessageBody;
public DateTime UpdatedAt;
}
var messages = new RecordSet<Message>();
messages.AddRange(...);
var byToUserID = messages.IndexBy(r => r.ToUserID);
byToUserID[7].FromUserID = 8; //Found member assignment
byToUserID[9] = byToUserID[10]; //Assignment (probably not desirable)
var byMessageBody = messages.IndexBy(r => r.MessageBody);
byMessageBody["hello"].ToUserID = 11;
byToUserID[12] = new Message() { MessageBody = "test1", ... }; //Where ToUserID in the supplied object will be overwritten.
byMessageBody["test1"].ToUserID == 12; //Evaluates to true
The benefit of this, is you get a semantic API that should be more predictable, but it also scales beyond 2 types.
The workaround can be based on explicit interfaces:
2nd version
public interface IDirectIndex<T1, T2>
{
T2 this[T1 key] { get; set; }
}
public interface IInvertedIndex<T1, T2>
{
T1 this[T2 key] { get; set; }
}
internal class DoubleIndexer<T1, T2> : IDirectIndex<T1, T2>, IInvertedIndex<T1, T2>
{
T2 IDirectIndex<T1, T2>.this[T1 key]
{
get => default;
set { Console.WriteLine($"T2 IDirectIndex<T1, T2>.this[T1 key]: {value}"); }
}
T1 IInvertedIndex<T1, T2>.this[T2 key]
{
get => default;
set { Console.WriteLine($"T1 IInvertedIndex<T1, T2>.this[T2 key]: {value}"); }
}
}
Test examples:
var int_string = new DoubleIndexer<int, string>();
((IDirectIndex<int, string>)int_string)[1] = "Hello"; // OK
((IInvertedIndex<int, string>)int_string)["Hello"] = 1; // OK
var int_byte = new DoubleIndexer<int, byte>();
((IInvertedIndex<int, byte>)int_byte)[1] = 134567; // OK
((IDirectIndex<int, byte>)int_byte)[134567] = 41; // OK
var int_int = new DoubleIndexer<int, int>();
((IInvertedIndex<int, int>)int_int)[1] = 1345; // OK
((IDirectIndex<int, int>)int_int)[13] = 5431; // OK
1st version
public interface IIndex<T1, T2>
{
T2 this[T1 key] { get; set; }
}
internal class DoubleIndexer<T1, T2> : IIndex<T1, T2>
{
public T1 this[T2 key]
{
get => default;
set { Console.WriteLine($"T1 this[T2 key]: {value}"); }
}
T2 IIndex<T1, T2>.this[T1 key]
{
get => default;
set { Console.WriteLine($"T2 IIndex<T1, T2>.this[T1 key]: {value}"); }
}
}
Test examples:
var int_string = new DoubleIndexer<int, string>();
((IIndex<int, string>)int_string)[1] = "Hello"; // OK
int_string["Hello"] = 1; // OK
var int_byte = new DoubleIndexer<int, byte>();
int_byte[1] = 134567; // OK
((IIndex<int, byte>)int_byte)[134567] = 41; // OK
var int_int = new DoubleIndexer<int, int>();
int_int[1] = 1345; // OK
((IIndex<int, int>)int_int)[13] = 5431; // OK
MSDN Indexers in Interfaces:
the fully qualified name is only needed to avoid ambiguity when the
class is implementing more than one interface with the same indexer
signature
I want to initialize an expandoObject from List.
internal class CarKeyValue {
public CarKey CarKey { get; set; }
public string Value1 { get; set; }
public string Value2 { get; set; }
}
public enum CarKey {
Brand = 1,
Model = 2,
Year = 3,
FactoryLocation = 4,
//more than 400 key here...
}
var car = new List<CarKeyValue>{
new CarKeyValue {CarKey = CarKey.Brand, Value1 = "Ford"},
new CarKeyValue {CarKey = CarKey.Model, Value1 = "Focus",Value2 = "Titanium"},
new CarKeyValue {CarKey = CarKey.Year, Value1 = "1995"},
new CarKeyValue {CarKey = CarKey.FactoryLocation, Value1 = "Turkey",Value2="Bursa"},
};
dynamic expando = new ExpandoObject();
foreach(var item in car){
expando.[item.CarKey].Value1 = item.Value1;
//Incorrect primary expression.
expando.[item.CarKey].Value2 = item.Value2;
}
How I do that? I need to use Expando Object. I try to use IDictionary<string,dynamic> but that thrown another exception.
Is there any possible way?
Yes, you can, but it makes no sense. You have to cast your expando object to IDictionary<string, object> or IDictionary<string, dynamic>.
IDictionary<string, object> expando = new ExpandoObject();
foreach (var item in car)
{
expando[item.CarKey.ToString()].Value1 = item.Value1;
}
The above code fails because you never assign a value to expando[item.CarKey.ToString()]. Instead you want to set a property from a non-existing object. Regular code would have thrown a NullReferenceException here. (You can read the above code as expando.SomeProperty.Value1, where SomeProperty is null.)
So once you have set the object to an instance of something, you can use it, but then there is not much use in using the ExpandoObject any more:
Foo foo = new Foo();
expando[item.CarKey.ToString()] = foo;
foo.Value1 = item.Value1;
My solution is here. I use IDictionary. Not neccessary using Foo() or something else. This code block working well.
IDictionary<string,dynamic> expando = new ExpandoObject();
foreach(var item in car) {
expando.Add(item.CarKey.ToString(),null);
expando[item.CarKey.ToString()] = new { Value1 = item.Value1,Value2 = item.Value2 };
}
I have a generic class with a lambda property defined as such:
public class Transformation<TProperty> : TransformationBase
{
public Func<TProperty, TProperty> Transform { get; private set; }
...
I'm trying to compile an Action that can call this Transform property (on a property of Foo). I don't know TProperty at compile-time. I've started with this:
private static Action<Foo> Compile(Transformation transformation)
{
var fooParameter = Expression.Parameter(typeof(Foo));
var changePropertyValue = Expression.Constant(transformation);
var transformProperty = Expression.Property(changePropertyValue, "Transform");
var transfromCall = Expression.Call(transformProperty, ?
}
How can I call/execute the transformProperty?
EDIT: Foo (which is known a compile time) has an untyped property Value which needs to be transformed using the Transform property of the Transformation:
public class Foo {
public object Value { get; set; }
}
So, hand-written as an example where TProperty is string it would be:
Foo foo = ... // coming from an external source
Transformation<string> tranformation = ... // coming from an external source
foo.Value = transformation.Transform((string)foo.Value);
Except that I don't know the exact type of the Transformation as it is defined in an external assembly. So, instead of string it could be int or something else. That's why I want to use Expression Trees to compile an Action for a given transformation, such that I can call:
Foo foo = ... // coming from an external source
TransformationBase transformation = ... // coming from an external source
Action<Foo> transform = Compile(transformation);
transform(foo); // should transform foo.Value using the Transform property of 'transformation'
Note: I made Transformation inherit from TransformationBase to clarify this discussion.
Your problems relate more to the lack of typing around your problem. Foo.Value is loosely typed, but your transform functions are strongly typed. Expression Trees are also strongly typed. Using them doesn't allow you to magically call code in a loosely typed manner.
The solution is either a lot of reflection, or some easy dynamic:
EDIT: I added CompileUntyped which uses ExpressionTrees.I also added CompileReflection, which uses Reflection without ExpressionTrees. I would recommend the one that uses dynamic. It is by far the easiest to read, hence the easiest to maintain.
class Program
{
static void Main(string[] args)
{
var testTransform = new Transformation<string>
{
Transform = s => s.ToUpper()
};
var a = Compile(testTransform);
var foo = new Foo
{
Value = "test"
};
a(foo);
//foo.Value is now TEST
}
public static Action<Foo> CompileReflection(TransformationBase transformation)
{
var f = transformation
.GetType()
.GetProperty("Transform")
.GetGetMethod()
.Invoke(transformation, null) as Delegate;
return foo => foo.Value = f.DynamicInvoke(foo.Value);
}
public static Action<Foo> Compile(TransformationBase transformation)
{
return new Action<Foo>(f =>
{
dynamic d = f.Value;
dynamic t = transformation;
f.Value = t.Transform(d);
});
}
public static Action<Foo> CompileUntyped(TransformationBase transformation)
{
var transformType = transformation.GetType();
var genericType = transformType.GetGenericArguments().First();
var fooParam = Expression.Parameter(typeof(Foo), "f");
var valueGetter = typeof(Foo).GetProperty("Value").GetGetMethod();
var valueSetter = typeof(Foo).GetProperty("Value").GetSetMethod();
var transformFuncMember = transformType.GetProperty("Transform").GetGetMethod();
//Equivalent to f => f.Value = transformation.Transform((T)f.Value)
//Where T is the generic type parameter of the Transformation, and f is of type Foo
var expression = Expression.Lambda<Action<Foo>>(
Expression.Call(
fooParam,
valueSetter,
Expression.Invoke(
Expression.Property(
Expression.Constant(transformation, transformType),
transformFuncMember
),
Expression.Convert(
Expression.Property(fooParam, valueGetter),
genericType
)
)
), fooParam
);
return expression.Compile();
}
}
public class TransformationBase { }
public class Transformation<TProperty> : TransformationBase
{
public Func<TProperty, TProperty> Transform { get; set; }
}
public class Foo
{
public object Value { get; set; }
}
Not sure what are you trying to do BUT if I understand your intentions - I do not see need for compiling Expressions:
private static Action<TProperty> Compile<TProperty>(Transformation<TProperty> transformation)
{
return new Action<TProperty>(p => transformation.Transform(p));
}
See an example, it should give you what you want.
void Main()
{
var dummyObject = new Dummy { Test = "Hello!" };
var propertyTransform = Create(dummyObject, "Test");
propertyTransform(dummyObject);
Console.WriteLine("Final transformation " + dummyObject.Test);
}
class Dummy {
public string Test { get; set; }
}
// Define other methods and classes here
public class Transformation<TProperty>
{
public Func<TProperty, TProperty> Transform { get; set; }
}
public static Action<TObj> Create<TObj>(TObj myObject, string property){
var prop = myObject
.GetType()
.GetProperty(property);
var val = prop.GetValue(myObject);
var transformation = Create((dynamic)val);
var transform = transformation.Transform;
return obj => {
var newValue = transform((dynamic)val);
prop.SetValue(myObject, newValue);
};
}
public static Transformation<TProperty> Create<TProperty>(TProperty property){
var transformation = new Transformation<TProperty>();
// just a dummy hijacking.
if(typeof(TProperty)==typeof(string)){
Func<string, string> test = input => "I am changed man!";
transformation.Transform = (dynamic)test;
}
return transformation;
}
Output:
Final transformation I am changed man!
How can I set generic type dynamically?
public class A
{
public int X { get; set; }
public A()
{
X = 9000;
}
}
public class Class1
{
public void Test()
{
List<A> theList = new List<A>() {
new A { X = 1 },
new A { X = 2 }
};
object testObj = theList;
var argType = testObj.GetType().GetGenericArguments()[0];
Foo(testObj as ICollection<argType>); // ?
}
public void Foo<T>(ICollection<T> items) where T:new()
{
T newItem = new T();
items.Add(newItem);
}
To do in "regular" c# you would use reflection to obtain the MethodInfo, then use MakeGenericMethod() and Invoke(). However, this is easier:
Foo((dynamic)testObj);
The reflection approach here is:
var method = typeof(Class1).GetMethod("Foo").MakeGenericMethod(argType);
method.Invoke(this, new object[] { testObj });
You can't do that, because in the Foo function you are supposed to do something with the collection, and there's no guarantee that the type will be safe.
The only way is using an "object" then casting to the proper type within the Fooo function.
I need to calculate a whole bunch of averages on an List of Surveys. The surveys have lots of properties that are int and double valued. I am creating a business object to handle all the calculations (there are like 100) and I'd rather not code 100 different methods for finding the average for a particular property.
I'd like to be able to have the UI pass a string (representing the property) and have the the business object return an average for that property.
So, like...
int AverageHeightInInches = MyObject.GetIntAverage("HeightInInches");
.
.
.
Then have linq code to calculate the result.
Thanks!
I have created this little example, it uses the System.Linq.Expression namespace to create a function that can calculate averages based on the property name. The function can be cached for later use, reflection is only used to create the function, not each time the function is executed.
EDIT: I removed the existing reflection example and updated the current example to show the ability to walk a list of properties.
static class Program
{
static void Main()
{
var people = new List<Person>();
for (var i = 0; i < 1000000; i++)
{
var person = new Person { Age = i };
person.Details.Height = i;
person.Details.Name = i.ToString();
people.Add(person);
}
var averageAgeFunction = CreateIntegerAverageFunction<Person>("Age");
var averageHeightFunction = CreateIntegerAverageFunction<Person>("Details.Height");
var averageNameLengthFunction = CreateIntegerAverageFunction<Person>("Details.Name.Length");
Console.WriteLine(averageAgeFunction(people));
Console.WriteLine(averageHeightFunction(people));
Console.WriteLine(averageNameLengthFunction(people));
}
public static Func<IEnumerable<T>, double> CreateIntegerAverageFunction<T>(string property)
{
var type = typeof(T);
var properties = property.Split('.'); // Split the properties
ParameterExpression parameterExpression = Expression.Parameter(typeof(T));
Expression expression = parameterExpression;
// Iterrate over the properties creating an expression that will get the property value
for (int i = 0; i < properties.Length; i++)
{
var propertyInfo = type.GetProperty(properties[i]);
expression = Expression.Property(expression, propertyInfo); // Use the result from the previous expression as the instance to get the next property from
type = propertyInfo.PropertyType;
}
// Ensure that the last property in the sequence is an integer
if (type.Equals(typeof(int)))
{
var func = Expression.Lambda<Func<T, int>>(expression, parameterExpression).Compile();
return c => c.Average(func);
}
throw new Exception();
}
}
public class Person
{
private readonly Detials _details = new Detials();
public int Age { get; set; }
public Detials Details { get { return _details; } }
}
public class Detials
{
public int Height { get; set; }
public string Name { get; set; }
}
Here is an example to do that.
class Survey
{
public int P1 { get; set; }
}
class MyObject
{
readonly List<Survey> _listofSurveys = new List<Survey> { new Survey { P1 = 10 }, new Survey { P1 = 20 } };
public int GetIntAverage(string propertyName)
{
var type = typeof(Survey);
var property = type.GetProperty(propertyName);
return (int)_listofSurveys.Select(x => (int) property.GetValue(x,null)).Average();
}
}
static void Main(string[] args)
{
var myObject = new MyObject();
Console.WriteLine(myObject.GetIntAverage("P1"));
Console.ReadKey();
}
if you are using linq2sql i would suggest DynamicLinq
you could then just do
datacontext.Surveys.Average<double>("propertyName");
the dynamic linq project provides the string overloads to IQueryable.
You can do this without reflection (both int and double are supported):
public static double Average(this IEnumerable<Survey> surveys, Func<Survey, int> selector)
{
return surveys.Average(selector);
}
public static double Average(this IEnumerable<Survey> surveys, Func<Survey, double> selector)
{
return surveys.Average(selector);
}
Usage:
var average1 = surveys.Average(survey => survey.Property1);
var average2 = surveys.Average(survey => survey.Property2);