Refactoring two lists of strings - c#

I have two lists of strings. One is object friendly name and other one is object class name.
"Car","Animal","Plane"
"MachineClass","AnimalClass","FlyClass".
I use friendly names to show user input and class names to dynamically create class instances by using reflection, so i need both lists and like you can see "Car" as friendly name can be bound to "Machine.cs".
I need some more creative way of working and translating both of these lists rather than using switch statement which converts from one string to other, those lists have numerous items and i can make small spelling which will cause error. Moreover sometimes, i send string of test name for evaluation whereas same problem with spellings can apply there.
I tried to think about using enums but still digits doesn't ring a bell for conversions between both lists.

public enum Things
{
Car,
Animal,
Plane
}
var dict = new Dictionary<Things, string> {
{ Things.Car, "MachineClass" },
{ Things.Animal, "AnimalClass" },
{ Things.Plane, "FlyClass" } };
string classname = dict[Things.Plane]; // FlyClass
Now if you wanted real types, that you can instantiate:
var realtypes = dict.ToDictionary(
kvp => kvp.Key,
kvp => System.Type.GetType("Namespace." + kvp.Value));
A fully working example is on http://ideone.com/TTuBP:
using System;
using System.Collections.Generic;
using System.Linq;
//public interface IThing {}
public class MachineClass /* : IThing */ { }
public class AnimalClass /* : IThing */ { }
public class Plane /* : IThing */ { }
public class Program
{
public enum Things
{
Car,
Animal,
Plane
}
private static readonly IDictionary<Things, string> _classNameMap =
new Dictionary<Things, string> {
{ Things.Car, "MachineClass" },
{ Things.Animal, "AnimalClass" },
{ Things.Plane, "FlyClass" } };
public static void Main(string[] args)
{
var realtypes = _classNameMap.ToDictionary(
kvp => kvp.Key,
kvp => System.Type.GetType(/*"Namespace." +*/ kvp.Value));
Type dynamicType = realtypes[Things.Plane]; // typeof(Namespace.FlyClass)
foreach (var realtype in realtypes)
Console.WriteLine("{0}, class {1}",
realtype.Key, realtype.Value);
}
}

Why not use a dictionary?
Dictionary<string, string> classMap_ = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
classMap_["Car"] = "MachineClass";
classMap_["Animal"] = "AnimalClass";
classMap_["Plane"] = "FlyClass":
Creating the appropriate class is as simple as:
string className = classMap_["Car"];

Use maps HashMap to maintain friendly name and class name mapping

I don't recomend to use reflection for creation objects of classes from performance point of view, insteed you can use lambda expressions to create objects
look at the following code
var animals = new Dictionary<string, Func<object>>
{
{"Animal 1", () => new MyAnimal1()},
{"Animal 2", () => new MyAnimal2()}
};
var createAnimal = animals["Animal 1"];
var animal = createAnimal();
where
private class MyAnimal1
{
}
private class MyAnimal2
{
}
insteed this classes you should use your classes.

Why not using databinding?
class Wrapper
{
public string UserFriendly{get;set;}
public string Technical{get;set;}
}
var data = new[]
{
new Wrapper("Car", "MachineClass"),
new Wrapper("Plane", "FlyClass"),
};
combo.Datasource = data;
combo.DisplayMember = "UserFriendly";
combo.ValueMember = "Technical";
Combo will display the friendlyname but when asking for SelectedValue you will get the technical name.

Related

Map [name,value] string values to class without reflection

I'm having a huge performance issue about mapping string property names and string property values to classes using reflection.
My issue now:
public class Person
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
// My class has around 100 properties
public string Property100 { get; set; }
}
I am mapping a key value pair collection to the class using reflection
[{"Property1": "some value"}, {"Property2": "something else"},{"Property3","Property4","value" }.....{"Property100","val"}]
It got to the point that I am now mapping around 10 000 class instances using reflection and the performance is to say it lightly bad.
Any ideas for eliminating the reflection would be greatly appreciated.
I see two options, if you need to avoid reflection for tasks like this(when code could be programatically generated).
First is Expressions I use it often, e.g. I saw some people write something like this
public class A
{
public Prop1 ...
....
public Prop100
public override ToString() => $"{nameof(Prop1)}={Prop1};...";
and so for all 100 properties, and always doing this manually.
And with Expression it can be easily automated, you just need to generate Expression for String.Concat and pass list of properties and names there.
For your example, it is not clear what are your data. How do you do lookup in the list?
Let's assume there is a dictionary<string,string>(you can transform your list of tuples to a dictionary), and all properties are strings as well.
Then we would need to generate a list assignment expressions like this
if(data.ContainsKey("Prop1")) result.Prop1 = data["Prop1"];
And the code would be complicated, anyway it would look like this
private static class CompiledDelegate<T>
{
public static Action<T, Dictionary<string, string>> initObject;
static CompiledDelegate()
{
var i = Expression.Parameter(typeof(Dictionary<string, string>), "i");
var v = Expression.Parameter(typeof(T), "v");
var propertyInfos = typeof(T).GetProperties().ToArray();
var t = new Dictionary<string, string>();
var contains = typeof(Dictionary<string, string>).GetMethod(nameof(Dictionary<string, string>.ContainsKey));
var getter = typeof(Dictionary<string, string>).GetProperties().First(x => x.GetIndexParameters().Length > 0);
var result = new List<Expression>();
foreach (var propertyInfo in propertyInfos)
{
var cst = Expression.Constant(propertyInfo.Name);
var assignExpression =
Expression.IfThen(Expression.Call(i, contains, cst),
Expression.Assign(Expression.PropertyOrField(v, propertyInfo.Name), Expression.MakeIndex(i, getter, new[] { cst })));
result.Add(assignExpression);
}
var block = Expression.Block(result);
initObject = Expression.Lambda<Action<T, Dictionary<string, string>>>(block, new ParameterExpression[] { v, i }).Compile();
}
}
It is an example, it would fail if there were non-string properties.
And it could be used like this
static void Main(string[] args)
{
var tst = new Test();
CompiledDelegate<Test>.initObject(tst, new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S2", "Value2" },
});
CompiledDelegate<Test>.initObject(tst, new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S1", "Value1" },
});
Console.ReadKey();
}
The second option is, actually, what it should be ideally imlemented like Using source generators I think such things do have to be done just in build time.
There is a lot of articles on msdn, for instance with samples. But it turned out to be not very easy to implement, even just a sample.
I can say, it didn't work for me, while I tried to do it according to samples.
In order to get it work I had to change TargetFramework to netstandard2.0, do something else...
But after all, when build was green, Visual Studio still showed an error.
Ok, it disappeared after VS restart, but still, that doesn't look very usable.
So, this is a generator, that creates a converter for every class with attribute.
It is again a sample, it doesn't check many things.
[Generator]
public class ConverterGenerator : ISourceGenerator
{
private static string mytemplate = #"using System.Collections.Generic;
using {2};
namespace GeneratedConverters
{{
public static class {0}Converter
{{
public static {0} Convert(Dictionary<string, string> data)
{{
var result = new {0}();
{1}
return result;
}}
}}
}}";
public static string GetNamespaceFrom(SyntaxNode s)
{
if (s.Parent is NamespaceDeclarationSyntax namespaceDeclarationSyntax)
{
return namespaceDeclarationSyntax.Name.ToString();
}
if (s.Parent == null)
return "";
return GetNamespaceFrom(s.Parent);
}
public void Execute(GeneratorExecutionContext context)
{
GetMenuComponents(context, context.Compilation);
}
private static void GetMenuComponents(GeneratorExecutionContext context, Compilation compilation)
{
var allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes());
var allClasses = allNodes.Where(d => d.IsKind(SyntaxKind.ClassDeclaration)).OfType<ClassDeclarationSyntax>();
var classes = allClasses
.Where(c => c.AttributeLists.SelectMany(a => a.Attributes).Select(a => a.Name).Any(s => s.ToString().Contains("DictionaryConverter")))
.ToImmutableArray();
foreach (var item in classes.Distinct().Take(1))
{
context.AddSource(item.Identifier.Text + "Converter", String.Format(mytemplate, item.Identifier.Text, SourceText.From(GenerateProperties(item)), GetNamespaceFrom(item)));
}
}
private static string GenerateProperties(ClassDeclarationSyntax s)
{
var properties = s.Members.OfType<PropertyDeclarationSyntax>();
return String.Join(Environment.NewLine,
properties.Select(p =>
{
var name = p.Identifier.Text;
return $"if(data.ContainsKey(\"{name}\")) result.{name} = data[\"{name}\"];";
}));
}
public void Initialize(GeneratorInitializationContext context)
{
}
}
and
static void Main(string[] args)
{
var t1 = GeneratedConverters.TestConverter.Convert(new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S2", "Value2" },
});
}
Best performance without reflection would be manual mapping.
It seems your key/value pair collection is regular JSON. So you could use the JSONTextReader from JSON.NET and read the string. Then manually map the JSON properties to the class properties.
Like so:
JsonTextReader reader = new JsonTextReader(new StringReader(jsonString));
while (reader.Read())
{
if (reader.Value != null)
{
// check reader.Value.ToString() and assign to correct class property
}
}
More info can be found on the JSON.NET website : https://www.newtonsoft.com/json/help/html/ReadingWritingJSON.htm

When to use generics and type checking?

Assume A through Z to be 26 classes I defined. In the following example:
private List<A> _listA;
private List<B> _listB;
// private List<C>, and so on, through...
private List<Z> _listZ;
private void setLabelA()
{
LabelA.Text = _listA.Count;
}
// private void setLabelB() exists
// and so does setLabelC()
// and so on, all the way through to...
private void setLabelZ()
{
LabelA.Text = _listZ.Count;
}
It seems to me that there is no way to shorten this other than the following:
private void setLabel<genericType>(List<genericType> list)
{
if(list is List<A>) LabelA.Text = _listA.Count;
else if(list is List<B>) LabelB.Text = _listB.Count;
else if(list is List<C>) LabelC.Text = _listC.Count;
// and so on...
else if(list is List<Z>) LabelZ.Text = _listZ.Count;
}
Overloading the function name doesn't reduce the number of lines of code:
private void setLabel(List<A> list)
{
LabelA.Text = _listA.Count;
}
private void setLabel(List<B> list)
{
LabelB.Text = _listB.Count;
}
I prefer to use the is operator to determine which Label to set, because it preserves space (in this scenario, 50 lines of meaningless brackets and 25 lines of slightly-different function names). However, a Stack Overflow user recommended that I not use generics, and instead use separate functions, one for each Label. Although this solution will work, I prefer to not do so.
Is there any benefit towards NOT using the is operator, and towards explicitly typing my functions?
The benefit is that your type checking is static, rather than dynamic. If someone passes in a List<SomeRandomeClassYouDontSupport> to the first method, then the code will compile and just not work properly at runtime. It'll either do nothing, throw an exception, or whatever you code it to do, but the point is that the caller won't be able to see that they did something wrong until they run the code.
When you have multiple overloads then the validation is done at compile time. If an unsupported type is provided then the code won't even compile rather than compiling and not working.
It's also an important semantic difference. Generics are there to say, "This method will work regardless of what the type is". When creating a list there are no right and wrong type arguments to provide. You can create a list of any type that you want. That's an appropriate use of generics, because lists are a conceptually generic data structure. Having several overloads is a way of saying, "This finite list of types is supported." You're in the latter case, so that makes that behavior clearer to the caller, so they'll understand what the method needs to do just by looking at its signature.
Having said all of that, it looks like this isn't even a situation where you should be doing either. If you really wanted to have a method accepting one of a finite number of types known at compile time as a parameter, overloads are the right way to do it, but in your case, you shouldn't be doing any of this at all. You should be binding these UI compontents to a view as mentioned in this comment.
Why not just make your own classes which derive their own fields automatically?
private class ListWithText : List<T>
{
int Text {
get { return this.Count; }
}
}
ListWithText<A> LabelA = new ListWithText<A>();
Console.WriteLine(LabelA.Text);
I will NOT comment about whether it is a good practice or not to do what you are doing :).
If the absence of a label for a given list is NOT the end of the world for you and if you rely on some naming conventions for your label fields so that all labels are named for example "LabelX" where X is your type that will be used for generic lists, you can do that:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Labels
{
class Program
{
static void Main(string[] args)
{
Container c = new Container();
c.ApplyLabels();
}
}
public class A
{
}
public class B
{
}
public class C
{
}
public class Container
{
private Label LabelA = new Label ();
private Label LabelB = new Label ();
private Label LabelC = new Label ();
private List<A> _listA = new List<A> ();
private List<B> _listB = new List<B> ();
private List<C> _listC = new List<C> ();
public void ApplyLabels ()
{
var allFields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Dictionary<Type, FieldInfo> listFields = new Dictionary<Type, FieldInfo>();
Dictionary<Type, FieldInfo> labelMappings = new Dictionary<Type, FieldInfo>();
Dictionary<string, Type> namespacesForListGenericTypes = new Dictionary<string, Type>();
List<FieldInfo> possibleLabelFields = new List<FieldInfo>();
foreach (var field in allFields)
{
if (field.FieldType.IsGenericType)
{
var genericTypeDef = field.FieldType.GetGenericTypeDefinition();
if (genericTypeDef == typeof (List<>))
{
var genericArgument = field.FieldType.GetGenericArguments()[0];
listFields.Add(genericArgument, field); // remember list fields and for each list what generic type it has!
namespacesForListGenericTypes[genericArgument.Name] = genericArgument;
}
}
else if (typeof (Label).IsAssignableFrom (field.FieldType))
{
possibleLabelFields.Add(field);
}
}
foreach (var possible in possibleLabelFields)
{
if (possible.Name.Length < 6) continue;
var typeName = possible.Name.Substring(5);
Type genericListType;
if (namespacesForListGenericTypes.TryGetValue (typeName, out genericListType))
{
labelMappings[genericListType] = possible;
}
}
foreach (var list in listFields)
{
FieldInfo destination;
if (false == labelMappings.TryGetValue (list.Key, out destination))
{
continue;
}
var destinationLabel = destination.GetValue(this) as Label;
if (destinationLabel == null) continue;
var listValue = list.Value.GetValue(this) as IList;
var cnt = listValue == null ? 0 : listValue.Count;
destinationLabel.Text = cnt.ToString();
}
}
}
public class Label
{
public string Text { get; set; }
}
}

ListBox Items are from Strings Declared in Other Class Possible?

related to this topic:
https://stackoverflow.com/questions/15170054/context-hint-using-combobox
Is there a way I can use the strings in my separate class:
namespace KeyWord
{
public class KeyWord
{
//Definitions
public String[] keywords = { "abstract", "as", "etc." };
}
}
to mylistbox items in my mainform?
lb = new ListBox();
Controls.Add(lb);
ty in advance
Sure. Try something like this.
KeyWord kw = new KeyWord();
foreach (string str in kw.keywords)
{
lb.Items.Add(str);
}
Or you can use databinding.
Also, if all you're doing is getting an array of strings from that class, you might want to use a static property so you don't have to instantiate an instance of that object. I would recommend using properties either way for exposing public data, instead of a public field.
Here's an example of using a static property, instead:
public class KeyWord
{
// Private field, only accessible within this class
private static string[] _keywords = { "abstract", "as", "etc." };
// Public Static Property, accessible wherever
public static string[] Keywords
{
get { return _keywords; }
set { _keywords = value; }
}
}
Then:
foreach (string str in KeyWord.Keywords)
{
lb.Items.Add(str);
}
Notice, I didn't instantiate the class in this example (no new KeyWords())

How to refactor these generic methods?

UPDATE: I should have mentioned in the original post that I want to learn more about generics here. I am aware that this can be done by modifying the base class or creating an interface that both document classes implement. But for the sake of this exercise I'm only really interested in solutions that do not require any modification to the document classes or their base class. I thought that the fact that the question involves extension methods would have implied this.
I have written two nearly identical generic extension methods and am trying to figure out how I might refactor them into a single method. They differ only in that one operates on List and the other on List, and the properties I'm interested in are AssetID for AssetDocument and PersonID for PersonDocument. Although AssetDocument and PersonDocument have the same base class the properties are defined in each class so I don't think that helps. I have tried
public static string ToCSVList<T>(this T list) where T : List<PersonDocument>, List<AssetDocument>
thinking I might then be able to test the type and act accordingly but this results in the syntax error
Type parameter 'T' inherits
conflicting constraints
These are the methods that I would like to refactor into a single method but perhaps I am simply going overboard and they would best be left as they are. I'd like to hear what you think.
public static string ToCSVList<T>(this T list) where T : List<AssetDocument>
{
var sb = new StringBuilder(list.Count * 36 + list.Count);
string delimiter = String.Empty;
foreach (var document in list)
{
sb.Append(delimiter + document.AssetID.ToString());
delimiter = ",";
}
return sb.ToString();
}
public static string ToCSVList<T>(this T list) where T : List<PersonDocument>
{
var sb = new StringBuilder(list.Count * 36 + list.Count);
string delimiter = String.Empty;
foreach (var document in list)
{
sb.Append(delimiter + document.PersonID.ToString());
delimiter = ",";
}
return sb.ToString();
}
Your implementation is basically reimplementing string.Join method, so you might try to make it simpler and more generic with some LINQ:
public static string ToCSVList<T>(this IEnumerable<T> collection)
{ return string.Join(",", collection.Select(x => x.ToString()).ToArray()); }
public static string ToCSVList(this IEnumerable<AssetDocument> assets)
{ return assets.Select(a => a.AssetID).ToCSVList(); }
public static string ToCSVList(this IEnumerable<PersonDocument> persons)
{ return persons.Select(p => p.PersonID).ToCSVList(); }
I think the way would be to let PersonDocument and AssetDocument inherit from a Document class, which would have an Id property, that stores your current PersonId or AssetId respectivly.
Make an abstraction, such as IDocument or an abstract class BaseDocument which exposes the id (which is the only field you are really using) and make both PersonDocument and AssetDocument implement that. Now make your generic method accept IDocument or BaseDocument instead.
How do you like this variant (a little bit simplified, but you should get the idea):
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var la = new List<AssetDocument> { new AssetDocument() {AssetID = 1} };
var result = la.ToCSVList(l => l.AssetID.ToString());
}
}
public class AssetDocument
{
public int AssetID { get; set; }
}
public static class GlobalExtensions
{
public static string ToCSVList<T>(this List<T> list, Func<T, string> propResolver)
{
var sb = new StringBuilder(list.Count * 36 + list.Count);
var delimiter = "";
foreach (var document in list)
{
sb.Append(delimiter);
sb.Append(propResolver(document));
delimiter = ",";
}
return sb.ToString();
}
}
}
This would work with any list (in case you don't care about the preallocated memory in StringBuilder even with any IEnumerable).
Update: Even if you want to keep your original extension methods, you can reduce them to one line of code with this.
What about making your method also take in a delegate to return the document.AssetID.ToString() for that list as appropriate?
Using Lamda expressions this could be reasonably lightweight, if a little ugly. A console application to demonstarate:
class Program
{
static void Main(string[] args)
{
List<string> strings = new List<string> { "hello", "world", "this", "is", "my", "list" };
List<DateTime> dates = new List<DateTime> { DateTime.Now, DateTime.MinValue, DateTime.MaxValue };
Console.WriteLine(ToCSVList(strings, (string s) => { return s.Length.ToString(); }));
Console.WriteLine(ToCSVList(dates, (DateTime d) => { return d.ToString(); }));
Console.ReadLine();
}
public static string ToCSVList<T, U>(T list, Func<U, String> f) where T : IList<U>
{
var sb = new StringBuilder(list.Count * 36 + list.Count);
string delimiter = String.Empty;
foreach (var document in list)
{
sb.Append(delimiter + f(document));
delimiter = ",";
}
return sb.ToString();
}
}
Whether this is the best approach or not, I leave as an exercise for the reader!
I only know java, so I can't give correct syntax, but the general approach should work:
define an interface Document, which gets implemented by PersonDocument and AssetDocument,
with the method
String getIdString();
Use a List as a parameter to you method. Note this is java syntax for a List of Something that inherits/extends from Document.
You could use Reflection for a bit of Duck Typing action!
I have assumed that your classes are called #class#Document and you want to concatenate the #class#ID properties. If the list contains classes that conform to this naming they will be concatenated. Otherwise they wont.
This is very much how the Rails framework operates, using Convention over Configuration.
Obviously such behaviour is more suited to dynamic languages such as Ruby. Probably the best solution for a more static language such as C# would be to refactor the base classes, use interfaces etc.. But that wasnt in the spec, and for educational purposes this is one way around things!
public static class Extensions
{
public static string ToCSVList<T> ( this T list ) where T : IList
{
var sb = new StringBuilder ( list.Count * 36 + list.Count );
string delimiter = String.Empty;
foreach ( var document in list )
{
string propertyName = document.GetType ().Name.Replace("Document", "ID");
PropertyInfo property = document.GetType ().GetProperty ( propertyName );
if ( property != null )
{
string value = property.GetValue ( document, null ).ToString ();
sb.Append ( delimiter + value );
delimiter = ",";
}
}
return sb.ToString ();
}
}
Usage (note no need for inheritance with Duck Typing - also works with any type!) :
public class GroovyDocument
{
public string GroovyID
{
get;
set;
}
}
public class AssetDocument
{
public int AssetID
{
get;
set;
}
}
...
List<AssetDocument> docs = new List<AssetDocument> ();
docs.Add ( new AssetDocument () { AssetID = 3 } );
docs.Add ( new AssetDocument () { AssetID = 8 } );
docs.Add ( new AssetDocument () { AssetID = 10 } );
MessageBox.Show ( docs.ToCSVList () );
List<GroovyDocument> rocs = new List<GroovyDocument> ();
rocs.Add ( new GroovyDocument () { GroovyID = "yay" } );
rocs.Add ( new GroovyDocument () { GroovyID = "boo" } );
rocs.Add ( new GroovyDocument () { GroovyID = "hurrah" } );
MessageBox.Show ( rocs.ToCSVList () );
...

Can anonymous class implement interface?

Is it possible to have an anonymous type implement an interface?
I've got a piece of code that I would like to work, but don't know how to do this.
I've had a couple of answers that either say no, or create a class that implements the interface construct new instances of that. This isn't really ideal, but I'm wondering if there is a mechanism to create a thin dynamic class on top of an interface which would make this simple.
public interface DummyInterface
{
string A { get; }
string B { get; }
}
public class DummySource
{
public string A { get; set; }
public string C { get; set; }
public string D { get; set; }
}
public class Test
{
public void WillThisWork()
{
var source = new DummySource[0];
var values = from value in source
select new
{
A = value.A,
B = value.C + "_" + value.D
};
DoSomethingWithDummyInterface(values);
}
public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
{
foreach (var value in values)
{
Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
}
}
}
I've found an article Dynamic interface wrapping that describes one approach. Is this the best way of doing this?
No, anonymous types cannot implement an interface. From the C# programming guide:
Anonymous types are class types that consist of one or more public read-only properties. No other kinds of class members such as methods or events are allowed. An anonymous type cannot be cast to any interface or type except for object.
While the answers in the thread are all true enough, I cannot resist the urge to tell you that it in fact is possible to have an anonymous class implement an interface, even though it takes a bit of creative cheating to get there.
Back in 2008 I was writing a custom LINQ provider for my then employer, and at one point I needed to be able to tell "my" anonymous classes from other anonymous ones, which meant having them implement an interface that I could use to type check them. The way we solved it was by using aspects (we used PostSharp), to add the interface implementation directly in the IL. So, in fact, letting anonymous classes implement interfaces is doable, you just need to bend the rules slightly to get there.
Casting anonymous types to interfaces has been something I've wanted for a while but unfortunately the current implementation forces you to have an implementation of that interface.
The best solution around it is having some type of dynamic proxy that creates the implementation for you. Using the excellent LinFu project you can replace
select new
{
A = value.A,
B = value.C + "_" + value.D
};
with
select new DynamicObject(new
{
A = value.A,
B = value.C + "_" + value.D
}).CreateDuck<DummyInterface>();
Anonymous types can implement interfaces via a dynamic proxy.
I wrote an extension method on GitHub and a blog post http://wblo.gs/feE to support this scenario.
The method can be used like this:
class Program
{
static void Main(string[] args)
{
var developer = new { Name = "Jason Bowers" };
PrintDeveloperName(developer.DuckCast<IDeveloper>());
Console.ReadKey();
}
private static void PrintDeveloperName(IDeveloper developer)
{
Console.WriteLine(developer.Name);
}
}
public interface IDeveloper
{
string Name { get; }
}
No; an anonymous type can't be made to do anything except have a few properties. You will need to create your own type. I didn't read the linked article in depth, but it looks like it uses Reflection.Emit to create new types on the fly; but if you limit discussion to things within C# itself you can't do what you want.
The best solution is just not to use anonymous classes.
public class Test
{
class DummyInterfaceImplementor : IDummyInterface
{
public string A { get; set; }
public string B { get; set; }
}
public void WillThisWork()
{
var source = new DummySource[0];
var values = from value in source
select new DummyInterfaceImplementor()
{
A = value.A,
B = value.C + "_" + value.D
};
DoSomethingWithDummyInterface(values.Cast<IDummyInterface>());
}
public void DoSomethingWithDummyInterface(IEnumerable<IDummyInterface> values)
{
foreach (var value in values)
{
Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
}
}
}
Note that you need to cast the result of the query to the type of the interface. There might be a better way to do it, but I couldn't find it.
The answer to the question specifically asked is no. But have you been looking at mocking frameworks? I use MOQ but there's millions of them out there and they allow you to implement/stub (partially or fully) interfaces in-line. Eg.
public void ThisWillWork()
{
var source = new DummySource[0];
var mock = new Mock<DummyInterface>();
mock.SetupProperty(m => m.A, source.Select(s => s.A));
mock.SetupProperty(m => m.B, source.Select(s => s.C + "_" + s.D));
DoSomethingWithDummyInterface(mock.Object);
}
Another option is to create a single, concrete implementing class that takes lambdas in the constructor.
public interface DummyInterface
{
string A { get; }
string B { get; }
}
// "Generic" implementing class
public class Dummy : DummyInterface
{
private readonly Func<string> _getA;
private readonly Func<string> _getB;
public Dummy(Func<string> getA, Func<string> getB)
{
_getA = getA;
_getB = getB;
}
public string A => _getA();
public string B => _getB();
}
public class DummySource
{
public string A { get; set; }
public string C { get; set; }
public string D { get; set; }
}
public class Test
{
public void WillThisWork()
{
var source = new DummySource[0];
var values = from value in source
select new Dummy // Syntax changes slightly
(
getA: () => value.A,
getB: () => value.C + "_" + value.D
);
DoSomethingWithDummyInterface(values);
}
public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
{
foreach (var value in values)
{
Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
}
}
}
If all you are ever going to do is convert DummySource to DummyInterface, then it would be simpler to just have one class that takes a DummySource in the constructor and implements the interface.
But, if you need to convert many types to DummyInterface, this is much less boiler plate.
Using Roslyn, you can dynamically create a class which inherits from an interface (or abstract class).
I use the following to create concrete classes from abstract classes.
In this example, AAnimal is an abstract class.
var personClass = typeof(AAnimal).CreateSubclass("Person");
Then you can instantiate some objects:
var person1 = Activator.CreateInstance(personClass);
var person2 = Activator.CreateInstance(personClass);
Without a doubt this won't work for every case, but it should be enough to get you started:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Publisher
{
public static class Extensions
{
public static Type CreateSubclass(this Type baseType, string newClassName, string newNamespace = "Magic")
{
//todo: handle ref, out etc.
var concreteMethods = baseType
.GetMethods()
.Where(method => method.IsAbstract)
.Select(method =>
{
var parameters = method
.GetParameters()
.Select(param => $"{param.ParameterType.FullName} {param.Name}")
.ToString(", ");
var returnTypeStr = method.ReturnParameter.ParameterType.Name;
if (returnTypeStr.Equals("Void")) returnTypeStr = "void";
var methodString = #$"
public override {returnTypeStr} {method.Name}({parameters})
{{
Console.WriteLine(""{newNamespace}.{newClassName}.{method.Name}() was called"");
}}";
return methodString.Trim();
})
.ToList();
var concreteMethodsString = concreteMethods
.ToString(Environment.NewLine + Environment.NewLine);
var classCode = #$"
using System;
namespace {newNamespace}
{{
public class {newClassName}: {baseType.FullName}
{{
public {newClassName}()
{{
}}
{concreteMethodsString}
}}
}}
".Trim();
classCode = FormatUsingRoslyn(classCode);
/*
var assemblies = new[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(baseType.Assembly.Location),
};
*/
var assemblies = AppDomain
.CurrentDomain
.GetAssemblies()
.Where(a => !string.IsNullOrEmpty(a.Location))
.Select(a => MetadataReference.CreateFromFile(a.Location))
.ToArray();
var syntaxTree = CSharpSyntaxTree.ParseText(classCode);
var compilation = CSharpCompilation
.Create(newNamespace)
.AddSyntaxTrees(syntaxTree)
.AddReferences(assemblies)
.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
//compilation.Emit($"C:\\Temp\\{newNamespace}.dll");
if (result.Success)
{
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
var newTypeFullName = $"{newNamespace}.{newClassName}";
var type = assembly.GetType(newTypeFullName);
return type;
}
else
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
return null;
}
}
}
public static string ToString(this IEnumerable<string> list, string separator)
{
string result = string.Join(separator, list);
return result;
}
public static string FormatUsingRoslyn(string csCode)
{
var tree = CSharpSyntaxTree.ParseText(csCode);
var root = tree.GetRoot().NormalizeWhitespace();
var result = root.ToFullString();
return result;
}
}
}

Categories

Resources