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 () );
...
Related
I actually asked a very similar question recently, but while the title mentioned classes, my content mostly referred to a tuple, and the (really great) answer reflected that. When I've tried to substitute a class in for the tuple, I get TargetParameterCountException: Parameter count mismatch. exception.
How can I get NHibernate to map to a Tuple or Class?
I have the following method to get a list of results from the database.
public static IList<T> Find<T>(DetachedCriteria crit) where T : class
{
lock (_locker)
{
return crit.GetExecutableCriteria(InstanceSession)
.List<T>();
}
}
This generally works well. However, I've changed a method that calls the method above from.
public IList<FooBarResult> FindResults(FooBarTask st)
{
return DataAccess.Find<FooBarResult>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))).ToList();
}
Which works, to this (as I don't want to return the whole of FooBarResult, just certain columns on it).
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(
Projections.Property("FieldOne") //this is a DateTime
)
.Add(
Projections.Property("FieldTwo") //this is a Guid
)
.SetResultTransformer(Transformers.AliasToBeanConstructor(typeConstructor))
)
);
}
And this is the class.
public class MyCustomClass
{
public MyCustomClass()
{
//placeholder
}
public MyCustomClass(DateTime FieldOne, Guid FieldTwo)
{
this.FieldOne = FieldOne;
this.FieldTwo = FieldTwo;
}
public DateTime FieldOne { get; set; }
public Guid FieldTwo { get; set; }
}
As mentioned earlier, when running the return crit.GetExecutableCriteria(InstanceSession).List<T>(); code I get a TargetParameterCountException: Parameter count mismatch. exception.
Is there any way I can make it return a list of my MyCustomClass?
I have not tested this, but you should use Transformers.AliasToBean take a look in to the aliases to let the transformer work:
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("FieldOne"), "FieldOne")
.Add(Projections.Property("FieldTwo"), "FieldTwo")
)
.SetResultTransformer(Transformers.AliasToBean(typeof(MyCustomClass)))
.List<MyCustomClass>()
}
In this line:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
you will get the first, default constructor and its signature obviously doesn't match. The simplest fix for your case is:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[1];
But the cleanest solution would be something along these lines (untested and also a bit simplified):
var typeConstructor = GetMatchingConstructorOrThrow<MyCustomClass>
(typeof(DateTime), typeof(Guid));
// ...
private ConstructorInfo GetMatchingConstructorOrThrow<T>(params Type[] requiredSignature)
where T : class
{
foreach (var c in typeof(T).GetConstructors())
{
var currentSignature = c.GetParameters().Select(p => p.ParameterType);
if (currentSignature.SequenceEqual(requiredSignature))
{
return c;
}
}
throw new NoMatchingConstructorFoundException();
}
I have a collection of object in lst of type DataResponse and what I would like to do is sum up all the properties that are int and decimal of this collection and assign the result of each property to another object DataContainerResponse that has the same exact property names(and types) as the those that are being summed up.
I can do this manually by typing out each property by hand and do a .Sum(s=>s.<propertyname>. But that so 90s. Below is my fruitless attempt to juice it out. Frankly, I never assigned a var to a lambda expression before and I don't even know if it's possible .Sum(s=><var name>);
public DataAggragationResponse doAggregation(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataContainerResponse rd = new DataContainerResponse();
//If I do it manually typing each prop by hand.
rd.VIOL = lst.Sum(s => s.VIOL);
//Automation!!!
foreach (PropertyInfo propertyInfo in typeof(DataResponse).GetProperties())
{
rd.GetType().GetProperties().SetValue(lst.Sum(s => propertyInfo.Name[0]));
}
}
If you want to go with full reflection, you can try something like the following. I didnt optimize the code, did it as fast as I can. So sorry for the messy look and Im assuming the property names are same in the aggregated result class and the unit class that you are aggregating against.
class Program
{
static void Main(string[] args)
{
var list = new List<DataResponse>();
list.Add(new DataResponse() { Stuff = 1, Stuff2 = 2 });
list.Add(new DataResponse() { Stuff = 1, Stuff2 = 2 });
Stopwatch watch = new Stopwatch();
watch.Start();
var response = DoAggregationReflection(list);
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
watch.Reset();
watch.Start();
var response2 = DoAggregation(list);
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
}
public static DataAggragationResponse DoAggregationReflection(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataAggragationResponse aggrResponse = new DataAggragationResponse();
var responseType = typeof(DataResponse);
var aggrResponseType = typeof(DataAggragationResponse);
foreach (PropertyInfo propertyInfo in typeof(DataResponse).GetProperties())
{
aggrResponseType.GetProperty(propertyInfo.Name).SetValue(aggrResponse, lst.Sum(x => (int)responseType.GetProperty(propertyInfo.Name).GetValue(x)));
}
return aggrResponse;
}
public static DataAggragationResponse DoAggregation(List<DataResponse> lst)
{
if (lst.Count == 0)
return null;
DataAggragationResponse aggrResponse = new DataAggragationResponse();
aggrResponse.Stuff = lst.Sum(x => x.Stuff);
aggrResponse.Stuff2 = lst.Sum(x => x.Stuff2);
return aggrResponse;
}
}
public class DataResponse
{
public int Stuff { get; set; }
public int Stuff2 { get; set; }
}
public class DataAggragationResponse
{
public int Stuff { get; set; }
public int Stuff2 { get; set; }
}
But, as a suggestion, if you want to go with this approach, its better if you can cache all the reflection invokes you're making as they are costly. And the 90's approach would still win in benchmark. Like the example above would benchmark like the following with the simple StopWatch.
1.8193
0.4476
Press any key to continue . . .
The first one is the execution time of DoAggregationReflection and the last one is the execution time of DoAggregation. You can optimize the reflection one as much as you want but I think it would still fail to compete with the basic one.
Sometime's the 90's are way better. ;) Although you'd still use LINQ to do the actual summation so that's not that 90's anymore as LINQ was born in 2007 according to wikipedia.
Hopefully this can help you. I wish I had kept the SO link to the question I pulled this from a while ago. Sorry to the original poster for not mentioning his/her name.
using System.Reflection;
public static Dictionary<string, string> GetPropertiesValue(object o)
{
Dictionary<string, string> PropertiesDictionaryToReturn = new Dictionary<string, string>();
foreach (MemberInfo itemMemberInfo in o.GetType().GetMembers())
{
if (itemMemberInfo.MemberType == MemberTypes.Property)
{
//object PropValue = GetPropertyValue(OPSOP, item.Name);
//string itemProperty = itemMemberInfo.Name;
//string itemPropertyValue = o.GetType().GetProperty(itemMemberInfo.Name).GetValue(o, null).ToString();
//Console.WriteLine(itemProperty + " : " + itemPropertyValue);
PropertiesDictionaryToReturn.Add(itemMemberInfo.Name, o.GetType().GetProperty(itemMemberInfo.Name).GetValue(o, null).ToString());
}
}
return PropertiesDictionaryToReturn;
}
It's not exactly what you need but, I think you could adapt it.
I would rather take a different approach. I would dynamically build and compile (once) something like this:
Func<DataContainerResponse, DataResponse, DataContainerResponse> aggregateFunc =
(result, item) =>
{
result.Prop1 += item.Prop1;
result.Prop2 += item.Prop2;
...
result.PropN += item.PropN;
return result;
}
(if you wonder why the signature is like the above, the answer is - because it can be used directly for the following Aggregate overload).
Here is how it can be done:
static readonly Func<DataContainerResponse, DataResponse, DataContainerResponse>
AggregateFunc = BuildAggregateFunc();
static Func<DataContainerResponse, DataResponse, DataContainerResponse> BuildAggregateFunc()
{
var result = Expression.Parameter(typeof(DataContainerResponse), "result");
var item = Expression.Parameter(typeof(DataResponse), "item");
var propertyTypes = new HashSet<Type> { typeof(decimal), typeof(int) };
var statements = item.Type.GetProperties()
.Where(p => propertyTypes.Contains(p.PropertyType))
.Select(p => Expression.AddAssign(
Expression.Property(result, p.Name),
Expression.Property(item, p)));
var body = Expression.Block(statements
.Concat(new Expression[] { result }));
var lambda = Expression.Lambda<Func<DataContainerResponse, DataResponse, DataContainerResponse>>(
body, result, item);
return lambda.Compile();
}
and the usage is simple:
public DataContainerResponse DoAggregation(List<DataResponse> source)
{
return source.Aggregate(new DataContainerResponse(), AggregateFunc);
}
I have this class:
public class allFields
{
public string EAN { get; set; }
public string title { get; set; }
public string qty { get; set; }
public string price { get; set; }
public DateTime date { get; set; }
}
And a function that return an anonymous type:
public IEnumerable<object> stockEtatQty()
{
List<allFields> afList = new List<allFields>();
var query = from x in ctx.book
where x.qty > 0
select x;
foreach (var item in query)
{
allFields af = new allFields();
af.EAN = item.EAN;
af.title = item.Titre;
af.qty = ""+item.Quantite;
afList.Add(af);
}
var q = from x in afList
select new { EAN=x.EAN, Title=x.title, Quantity=x.qty };
return q; //q is a IEnumerable<'a> where a is new {string EAN, string Title, string Quantity}
}
In my WinForm a use this function as below:
private void QuantityToolStripMenuItem_Click(object sender, EventArgs e)
{
ServiceStock sstock = new ServiceStock();
var q = sstock.stockEtatQty().ToList();// q is a list<object>
string str = "";
foreach (var item in q)
{
str += item + Environment.NewLine;
}
MessageBox.Show(str);
}
The result is:
{ EAN = 1, Title = CSharp Security, Quantity = 970 }
{ EAN = 2, Title = MISC, Quantity = 100 }
...
What I want?
I want not like the result above, but separate each field apart of the item in the loop foreach, e.g get item.EAN, item.Title and item.Quantity.
If there is no solution for my problem I would like to know an alternative,
Thanks for help.
The obvious solution is to create a custom type (let's call it BookInfo) and return a IEnumerable<BookInfo> instead of a IEnumerable<object> (and maybe override ToString if you want to put the formatting into this class itself).
Then you can easily format the output.
public class BookInfo
{
public string EAN {get;set;}
public string Title {get;set;}
public int Quantity {get;set;}
}
public IEnumerable<BookInfo> stockEtatQty()
{
...
var q = from x in afList
select new BookInfo { EAN=x.EAN, Title=x.title, Quantity=x.qty };
return q;
}
private void QuantityToolStripMenuItem_Click(object sender, EventArgs e)
{
ServiceStock sstock = new ServiceStock();
var q = sstock.stockEtatQty();
var message = string.Join(Environment.NewLine,
q.Select(item => String.Format("{0} {1} {2}", item.EAN, item.Title, item.Quantity)));
MessageBox.Show(message);
}
Since the static type information about the object of anonymous type is lost by the time that you exit stockEtatQty() method, you could cast the object to dynamic and access fields like this:
str = string.Join(Environment.NewLine, q.Cast<dynamic>().Select(item =>
string.Format("{0} {1} {2}", item.EAN, item.Title, item.Quantity)
));
The cast to dynamic tells the compiler that EAN, Title, and Quantity need to be resolved at runtime.
Note that I also replaced the foreach loop with a call to string.Join to improve performance: repeated string concatenation creates unnecessary partial string objects, which string.Join avoids. Another solution would be to use StringBuider instead of string concatenation +=.
stockEtatQty is in a project (Service) and QuantityToolStripMenuItem_Click is in another project (View)
Unfortunately, this means that you would not be able to use anonymous types: anonymous types are generated with internal visibility, limiting their use to the assembly in which they are produced. You can use a work-around based on ExpandoObject described in this answer:
var q = afList.Select(x => {
dynamic res = new ExpandoObject();
res.EAN=x.EAN;
res.Title=x.title;
res.Quantity=x.qty;
return res;
});
Create a new class that represents the new object structure and return that.
var q = from x in afList
select new SmallerType { EAN=x.EAN, Title=x.title, Quantity=x.qty };
WinForm Function
foreach (SmallerType item in q)
{
//
}
You can use collection of dynamic objects instead of simple objects as return type of your method:
public IEnumerable<dynamic> stockEtatQty()
Then you will not have IntelliSense but at runtime properties will be found:
foreach (var item in sstock.stockEtatQty())
str += String.Format("{0}", item.EAN) + Environment.NewLine;
But I suggest you to create custom class with EAN, Title and Quantity properties. Or just use your allFields instead of anonymous objects.
Consider also to use StringBuilder for string creation to avoid creating lot of in-memory strings:
var builder = new StringBuilder();
foreach (var item in sstock.stockEtatQty())
builder.AppendFormat("{0}{1}", item.EAN, Environment.NewLine);
MessageBox.Show(builder.ToString());
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.
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;
}
}
}