Reduce duplication - Create delegate from an instance method - c#

I am working with an existing, slightly complex relationship between objects. After some refactoring for the sake of understandability, my code now looks like this:
TemplateColorList colors = new TemplateColorList();
var template = new Template {
TextElements = CreateTextElements(textElementData,
/* -> */ (textElement, colorParam1, colorParam2) => colors.AddTextColor(textElement, colorParam1, colorParam2)
),
ClipArtElements = CreateClipArtElements(clipArtElementData,
/* -> */ (clipArtElement, colorParam) => colors.AddClipArtColor(clipArtElement, colorParam)
),
Colors = colors,
};
I see duplication that I think can be removed, though - The delegates are just passing parameters as-is to colors methods. Is there a way to create a delegate from an instance method (not static) without duplicating the parameters?

Converting comments into an answer...
"Isn't it just CreateTextElements( textElementData, colors.AddTextColor ) without this extra delegate?" - #WiktorZychla
"If you've ever forgotten the parenthesis on a method call, you might have gotten a compiler error: Cannot convert method group to something. This is the opposite. Now you want to refer to the method without parenthesis or arguments because the method is the argument." - #ScottHannen (emphasis mine)
Thanks for the help! I was wrongly making an assumption that the types wouldn't work out here. Taking their advice, my code now looks like:
TemplateColorList colors = new TemplateColorList();
var template = new Template {
TextElements = CreateTextElements(textElementData, colors.AddTextColor),
ClipArtElements = CreateClipArtElements(clipArtElementData, colors.AddClipArtColor),
Colors = colors,
};

Related

generate random parameter value for a method without knowing the parameter type

What problem do I want to solve? Via reflection I want to execute code (running instance methods and also static methods) where I dont know beforehand how the method to be run is defined.
Lets say I have a MethodInfo that I want to invoke. I have no idea what parameters it has, so I do following.
first I check that method params are valid (if not valid then method is not invoked):
private static IEnumerable<Type> GetValidMethodTypes()
{
var validTypes = new List<Type>();
validTypes.AddRange(new[]
{
typeof (SByte),
typeof(String[]),
//etc...
});
return validTypes;
}
Then I generate random values based on param type:
public object RandomizeParamValue(string typeName)
{
switch (typeName)
{
case "SByte":
{
//return randomized value
}
case "String[]":
{
//return randomized value
}
//etc...
}
}
for example, a randomized value for String[] would be ["a","ab", "ccc"] or ["aa", "b"]. The formula is: new string[random size between 1 and 5 ] that contains random strings with random lengths. Everything super random :)
The problem is that this works only with what types I support in my code. I could offcourse add support for many many more types but it is much work. I would like to make this much more generic but I dont really know how. I have googled this but found nothing. Anyone knows of a solution/known pattern for this kind of problem?
I can re-formulate the question like this: How can I, via reflection, invoke following method:
void SomeMethod(unknowntypeatcompiletime param);
where unknowntypeatcompiletime could be anything.
It is really impossible to support types that you do not know prior to run-time.
However, it is quite easy to provide a dynamic way of adding types.
Try something like this:
public class Randomizer
{
private Dictionary<Type, Delegate> _randoms
= new Dictionary<Type, Delegate>();
public void Add<T>(Func<T> generate)
{
_randoms.Add(typeof(T), generate);
}
public T RandomizeParamValue<T>()
{
return ((Func<T>)_randoms[typeof(T)])();
}
}
You can then add the random delegates quite easily like this:
var rz = new Randomizer();
var rnd = new Random();
rz.Add(() => rnd.Next());
rz.Add(() => new [] { "a", "b", "c" }.ElementAt(rnd.Next(0, 3)));
Now I can easily call this code to get the random values:
var randIntegers = rz.RandomizeParamValue<int>();
var randStrings = rz.RandomizeParamValue<string>();
Very easy. Let me know if this helps.
There is no straightforward way to have a randomizer which will work for any possible type.
Depending on what you want to achieve, you might find some of the Mock and TDD frameworks, such as Moq or AutoFixture, useful (latter one can create objects with random data). They create however mocked objects, and it is an open question to what level they can do randomizing.
Another way is to have some sort of values seed in a file outside of your application. That seed file can contain object graphs of the possible types, of which one is randomly chosen. The file can be loaded at runtime and thus would not require recompiling. This solution would however require you to extend seed as soon you want to support new types.

use a variable value in an expression?

Let's say that I have many resource files: a.resx, b.resx and c.resx
and I use it like this:
groupSettingsLogin.Caption = Resources.a.login_caption;
or
groupSettingsLogin.Caption = Resources.b.login_caption;
If I have a global variable public String ResourceName and I set this at start at a certain value:
MyGlobalVariables.ResourceName = "a";
then can I somehow refer to the resource dynamically as:
groupSettingsLogin.Caption = Resources."MyGlobalVariables.ResourceName".login_caption;
I know the above line is not correct but is there a way to to something like this?
Or if not is there an alternative way for it?
You can use this
var resourceManager = new ResourceManager("YourNamespace." + MyGlobalVariables.ResourceName, Type.GetType("YourNamespace." + MyGlobalVariables.ResourceName).Assembly);
var login_caption = resourceManager.GetString("login_caption", CultureInfo.CurrentCulture);
I've checked this works fine. Previous answer was incorrect
Try this:
// MyGlobalVariables.Resources is `dynamic`
MyGlobalVariables.Resources = Resources.a;
groupSettingsLogin.Caption = MyGlobalVariables.Resources.login_caption;
Look into the generated code. There you can see how it itself accesses the underlying data. Should be very easy. Single method call. There's no magic underneath the generated properties. They are a thin facade. I once looked but I don't remember what's there.

Object oriented design, interacting objects

This problem reminds me of the minigame Doodle God. There are several objects and some of them can interact with each other and form new objects. Each object is naturally its own class: water, fire, air, etc. These all inherit from the same base class. The water and fire objects, for example, could be combined to form an ash object which can be used in new combinations.
The problem is figuring out an elegant way to handle all the possible combinations. The most obvious, but horribly unmaintainable, solution would be creating a function that takes any two objects as parameters and uses a huge switch block to compare typenames and figure out what kind of object (if any) should be returned when these two interact. It is also important that combine(a, b) should always equal combine(b, a).
What would be a maintainable and efficient design for this scenario?
We had to take code for this in a game to collide items. We ended up going for a two dimensional structure that stored a bunch of delegate methods.
| air | wind | fire
air |combine(air,air)|combine(air,wind) |combine(air,fire)
wind | |combine(wind,wind)|combine(wind,fire)
fire | | |combine(fire,fire)
with a bit of thinking, you only need to populate just over half of the combining matrix.
You could (for instance):
lookup =
new Dictionary<
Tuple<Type, Type>,
Func<ICombinable, ICombinable, ICombinable>();
lookup.Add(
Tuple.Create(typeof(Air), typeof(Fire)),
(air,fire) => return new Explosion());
Then have a single method:
ICombinable Combine(ICombinable a,ICombinable b)
{
var typeA = a.GetType();
var typeB = b.GetType();
var typeCombo1 = Tuple.Create(typeA,typeB);
Func<ICombinable,ICombinable,ICombinable> combineFunc;
if(lookup.TryGetValue(typeCombo1, out combineFunc))
{
return combineFunc(a,b);
}
var typeCombo2 = Tuple.Create(typeB,typeA);
if(lookup.TryGetValue(typeCombo2, out combineFunc))
{
return combineFunc(b,a);
}
//throw?
}
All game objects are already designed in some way. They are either hardcoded or read at runtime from a resource.
This data structure can easily be stored in a Dictionary<Element, Dictionary<Element, Element>>.
var fire = new FireElement();
var water = new WaterElement();
var steam = new SteamElement();
_allElements = Dictionary<Element, Dictionary<Element,Element>>
{
new KeyValuePair<Element, Dictionary<Element, Element>>
{
Key = fire,
Value = new KeyValuePair<Element, Element>
{
Key = water,
Value = steam
}
},
new KeyValuePair<Element, Dictionary<Element, Element>>
{
Key = water,
Value = new KeyValuePair<Element, Element>
{
Key = fire,
Value = steam
}
}
}
When loading or defining the elements, you can just duplicate them, as there'll at most be a few hundred. The overhead is neglectable for the ease of coding IMO.
The keys of _allElements contain all existing, combinable elements. The value of _allElements[SomeElement] yields yet another dictionary, which you can access on the elment you wish to combine it with.
This means you can find the resulting element of a combination with the following code:
public Element Combine(Element element1, Element element2)
{
return _allElements[element1][element2];
}
Which, when called as such:
var resultingElement = Combine(fire, water);
Yields steam, the same result as were Combine(water, fire) called.
Untested, but I hope the principle applies.
Exactly this is the right place for interfaces. With them you can avoid the big switch and each element class can implement its own behaviour of interacting with another elemt class.
I would propose using an Abstract Factory returning a specific kind of interface, lets say InteractionOutcome. You would not escape the need of using a switch-case but you would end up with something much more maintenable using different factories for each "construction".
Hope I helped!

Compile a C# Array at runtime and use it in code?

I know C# code can be compiled at runtime using C#. However I'm very very shaky at it since I just read about it a few minutes ago. I learn a lot better by examples. So tell me. If I want to compile something like:
// MapScript.CS
String[] LevelMap = {
"WWWWWWWWWWWWWWWWWWW",
"WGGGGGGGGGGGGGGGGGW",
"WGGGGGGGGGGGGGGGGGW",
"WWWWWWWWWWWWWWWWWWW" };
and use this array in my code, how would I go about it?
In pseudocode I want to do something like this:
Open("MapScript.CS");
String[] levelMap = CompileArray("levelMap");
// use the array
LINQ Expression trees are probably the friendliest way of doing this: Perhaps something like:
http://msdn.microsoft.com/en-us/library/system.linq.expressions.newarrayexpression.aspx
http://msdn.microsoft.com/en-us/library/bb357903.aspx
You can also generate the IL using OpCodes (OpCodes.Newarr). Easy if you are comfortable with stack-based programming (otherwise, can be challenging).
Lastly, you can use the CodeDom (which your pseudocode resembles), but--while the most powerful tool--it is less ideal for quick dynamic methods. It requires file system permissions and manual reference resolution since you are working closely with the compiler.
Sample from MSDN
var ca1 = new CodeArrayCreateExpression("System.Int32", 10);
var cv1 = new CodeVariableDeclarationStatement("System.Int32[]", "x", ca1);
Source - Creating Arrays with the Code DOM
If you want a straight up raw compile of a string, you can omit the object-oriented treatment of the statements and instead just build a big string. Something like:
var csc = new CSharpCodeProvider( new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } } );
var cp = new CompilerParameters() {
GenerateExecutable = false,
OutputAssembly = outputAssemblyName,
GenerateInMemory = true
};
cp.ReferencedAssemblies.Add( "mscorlib.dll" );
cp.ReferencedAssemblies.Add( "System.dll" );
cp.ReferencedAssemblies.Add( "System.Core.dll" );
StringBuilder sb = new StringBuilder();
// The string can contain any valid c# code, but remember to resolve your references
sb.Append( "namespace Foo{" );
sb.Append( "using System;" );
sb.Append( "public static class MyClass{");
// your specific scenario
sb.Append( #"public static readonly string[] LevelMap = {
""WWWWWWWWWWWWWWWWWWW"",
""WGGGGGGGGGGGGGGGGGW"",
""WGGGGGGGGGGGGGGGGGW"",
""WWWWWWWWWWWWWWWWWWW"" };" );
sb.Append( "}}" );
// "results" will usually contain very detailed error messages
var results = csc.CompileAssemblyFromSource( cp, sb.ToString() );
It appears that you are wanting to compile C# code in order to load a list of strings in a text (C#) file into a string array variable.
You don't need a c# compiler to load a list of strings from a text file into an array in memory. Just put one string per line in your text file, and read the file line by line in your code, adding each line to a List<String>. When you're done, list.ToArray() will produce your array of strings.
You can create a class CompiledLevel that inherits from ILevel which proposes a static property Level of type String[].
Then, before compiling, create a fake CompiledLevel.cs file built from a template of class filled with content of LevelMap (wwwggg...) (sort of concatenation).
One compiled, call Level property on the compiled class.
Create a service/factory/whatever to make it fancy :)

C#: Dynamically Constructing Variables

I get from an input a group of double variables named: weight0, weight1...weight49.
I want to dynamically insert them into a double Array for easier manipulation.
But instead of calling each one like: Weights[0] = weight0...Weights[49] = weight49 I want to do it with a single loop.
Is there a way to do it?
No, basically - unless you mean at the same time that you create the array:
var weights = new[] {weight0, weight1, weight2, ... , weight48, weight49};
Personally, I'd be tempted to get rid of the 50 variables, and use the array from the outset, but that may not be possible in all cases.
you could use reflection to determine the index of the array from the variable names but this is far from efficient. See this post for details.
I would try to do it with a KeyValuePair- Listobject
// sample data
var weight = 1.00;
// create a list
var tmp = new List<KeyValuePair<string,object>>();
// Here you can add your variables
tmp.Add(new KeyValuePair<string,object>("weights" + tmp.Count.ToString()
, weight));
// If needed convert to array
var weights = tmp.ToArray();
// get the information out of the array
var weightValue = weights[0].Value;
var weightKey = weights[0].Key;
I think this will give you all the options, you might need for the array. Give it a try.
I'm putting this up because you can do it - so long as these variables are actually fields/properties. Whether you should is another matter - this solution, while reusable, is slow (needs delegate caching) and I have to say I agree with Marc Gravell - consider using an array throughout if you can.
If the variables are properties then it needs changing. Also if you need to write the array back to the variables in one shot (because this solution generates an array with copies of all the doubles, I wouldn't consider creating an object array with boxed doubles), that requires another method...
So here goes. First a holy wall of code/extension method:
//paste this as a direct child of a namespace (not a nested class)
public static class SO8877853Extensions
{
public static TArray[] FieldsToArray<TObj, TArray>(this TObj o,string fieldPrefix)
{
if(string.IsNullOrWhiteSpace(fieldPrefix))
throw new ArgumentException("fieldPrefix must not null/empty/whitespace",
"fieldPrefix");
//I've done this slightly more expanded than it really needs to be...
var fields = typeof(TObj).GetFields(System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic)
.Where(f =>f.Name.StartsWith(fieldPrefix) && f.FieldType.Equals(typeof(TArray)))
.Select(f =>new{ Field = f, OrdinalStr = f.Name.Substring(fieldPrefix.Length)})
.Where(f => { int unused; return int.TryParse(f.OrdinalStr, out unused);})
.Select(f => new { Field = f.Field, Ordinal = int.Parse(f.OrdinalStr) })
.OrderBy(f => f.Ordinal).ToArray();
//doesn't handle ordinal gaps e.g. 0,1,2,7
if(fields.Length == 0)
throw new ArgumentException(
string.Format("No fields found with the prefix {0}",
fieldPrefix),
"fieldPrefix");
//could instead bake the 'o' reference as a constant - but if
//you are caching the delegate, it makes it non-reusable.
ParameterExpression pThis = Expression.Parameter(o.GetType());
//generates a dynamic new double[] { var0, var1 ... } expression
var lambda = Expression.Lambda<Func<TObj, TArray[]>>(
Expression.NewArrayInit(typeof(TArray),
fields.Select(f => Expression.Field(pThis, f.Field))), pThis);
//you could cache this delegate here by typeof(TObj),
//fieldPrefix and typeof(TArray) in a Dictionary/ConcurrentDictionary
return lambda.Compile()(o);
}
}
The extension method above will work on any type. It's generic over both the instance type and desired array type to simplify the creation of the lambda in code - it doesn't have to be generic though.
You pass in the name prefix for a group of fields - in your case "weight" - it then searches all the public and private instance fields for those with that prefix that also have a suffix which can be parsed into an integer. It then orders those fields based on that ordinal. It does not check for gaps in the ordinal list - so a type with weight0 and weight2 would work, but would only create a two-element array.
Then it bakes a dynamic piece of code using Expression trees, compiles it (at this point, as mentioned in the code, it would be good to cache the delegate against TObj and TArray for future use) and then executes it, returning the result.
Now add this to a test class in a standard unit test project:
private class SO8877853
{
private double field0 = 1.0;
private double field1 = -5.0;
private double field2 = 10.0;
public double[] AsArray()
{
//it would be nice not to have to pass both type names here - that
//can be achieved by making the extension method pass out the array
//via an 'out TArray[]' instead.
return this.FieldsToArray<SO8877853, double>("field");
}
}
[TestMethod]
public void TestThatItWorks()
{
var asArray = new SO8877853().AsArray();
Assert.IsTrue(new[] { 1.0, -5.0, 10.0 }.SequenceEqual(asArray));
}
Like I say - I'm not condoning doing this, nor am I expecting any +1s for it - but I'm a sucker for a challenge :)

Categories

Resources