I have this class :
public class Person : ICloneable
{
public string FirstName { get; set; }
public string LastName { get; set; }
public object Clone()
{
return this;
}
}
An extension method :
public static class MyHelper
{
public static IEnumerable<T> Clone<T>(this IEnumerable<T> collection) where T : ICloneable
{
return collection.Select(item => (T)item.Clone());
}
}
I'd like use it in this case :
var myList = new List<Person>{
new Person { FirstName = "Dana", LastName = "Scully" },
new Person{ FirstName = "Fox", LastName = "Mulder" }
};
List<Person> myCopy = myList.Clone().ToList<Person>();
When I change in the "immediat window" a value of myCopy, there is a change in the orginial list too.
I'd like have both list completely independent
I missed something ?
Your implementation of Clone is wrong.
Try this:
public object Clone()
{
return MemberwiseClone();
}
Your clone method returns the same object.
You should implement it like this
public class Person : ICloneable
{
public string FirstName { get; set; }
public string LastName { get; set; }
public object Clone()
{
return new Person { FirstName = this.FirstName, LastName = this.LastName };
}
}
Apart from the issue with your Clone method inside your Person class you need to return a new list in your extension method also
return collection.Select(item => (T)item.Clone()).ToList();
This is because the Select method is from Linq which uses deferred execution. If you change the original list then the list of 'myCopy' will also change.
Related
I need a method that returns a keySelector, which can be used when invoking an OrderBy expression. The problem is that a keySelector is a generic delegate and I would like the method to return keySelectors with different data types on TKey:
Func<TSource,TKey> keySelector
I would like to accomplish this, but instead of using lambda expressions a method that returns a keySelector (TKey=string or int):
IEnumerable<Person> orderedByFirstName = persons.OrderBy(p => p.FirstName);
IEnumerable<Person> orderedByAge = persons.OrderBy(p => p.Age);
Is it possible to have a method that returns keySelectors with different types on TKey in some way? It isn't possible to return lambda expressions, but something like that...
As long as the method only returns keySelectors of data type string everything works fine:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class Behavior
{
public virtual string GetOrderByKeySelector(Person p)
{
return p.FirstName;
}
}
public class SpecializedBehavior : Behavior
{
public override string GetOrderByKeySelector(Person p)
{
return p.LastName;
}
}
List<Person> persons = new List<Person>
{
new Person{Age=10, FirstName="Pelle", LastName="Larsson"},
new Person{Age=90, FirstName="Nils", LastName="Nilsson"},
new Person{Age=15, FirstName="Olle", LastName="Johansson"},
new Person{Age=30, FirstName="Kalle", LastName="Svensson"}
};
Used like this:
SpecializedBehavior behavior = new SpecializedBehavior();
IEnumerable<Person> orderedResult = persons.OrderBy(behavior.GetOrderByKeySelector);
How about taking in the collection to the method instead.
void Main()
{
SpecializedBehavior behavior = new SpecializedBehavior();
IEnumerable<Person> orderedResult = behavior.Sort(persons);
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class Behavior
{
public virtual IEnumerable<Person> Sort(IEnumerable<Person> persons)
{
return persons.OrderBy(p => p.FirstName);
}
}
public class SpecializedBehavior : Behavior
{
public override IEnumerable<Person> Sort(IEnumerable<Person> persons)
{
return persons.OrderBy(p => p.Age);
}
}
List<Person> persons = new List<Person>
{
new Person{Age=10, FirstName="Pelle", LastName="Larsson"},
new Person{Age=90, FirstName="Nils", LastName="Nilsson"},
new Person{Age=15, FirstName="Olle", LastName="Johansson"},
new Person{Age=30, FirstName="Kalle", LastName="Svensson"}
};
This answer is just to illustrate #LasseVågsætherKarlsen's comment and all the credit should go to him:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class PersonByFirstNameComparer : IComparer<Person>
{
public int Compare(Person left, Person right) =>
left.FirstName.CompareTo(right.FirstName);
}
public class Behavior
{
public virtual IComparer<Person> GetComparer() => PersonByFirstNameComparer();
}
public class PersonByLastNameComparer : IComparer<Person>
{
public int Compare(Person left, Person right) =>
left.LastName.CompareTo(right.LastName);
}
public class SpecializedBehavior : Behavior
{
public override IComparer<Person> GetComparer() => new PersonByLastNameComparer();
}
which can be used the following way:
public static void Main()
{
var people = new List<Person>
{
new Person{Age=10, FirstName="Pelle", LastName="Larsson"},
new Person{Age=90, FirstName="Nils", LastName="Nilsson"},
new Person{Age=15, FirstName="Olle", LastName="Johansson"},
new Person{Age=30, FirstName="Kalle", LastName="Svensson"}
};
var standardBehavior = new Behavior();
IEnumerable<Person> orderedPeople1 =
people.OrderBy(p => p, standardBehavior.GetComparer());
foreach (Person p in orderedPeople1)
{
Console.WriteLine($"{p.FirstName} {p.LastName}");
}
var specializedBehavior = new SpecializedBehavior();
IEnumerable<Person> orderedPeople2 =
people.OrderBy(p => p, specializedBehavior.GetComparer());
foreach (Person p in orderedPeople2)
{
Console.WriteLine($"{p.FirstName} {p.LastName}");
}
}
Link to fiddle
I created substitutes for Person and AddressBook classes in the unit Test.
The AddressBook class contains properties of type Person and name: SamplePerson.
public interface IAddressBook
{
Person SamplePerson { get; set; }
}
public class AddressBook : IAddressBook
{
public Person SamplePerson { get; set; }
public AddressBook(Person samplePerson)
{
SamplePerson = samplePerson;
}
}
public interface IPerson
{
string GetName(string name);
}
public class Person : IPerson
{
public string GetName(string name)
{
return name;
}
}
public void TestMethod1()
{
var personMock = Substitute.For<IPerson>();
var addressBookMock = Substitute.For<IAddressBook>();
addressBookMock.SamplePerson.Returns(personMock); //not working
addressBookMock.SamplePerson = personMock; //not working
addressBookMock.SamplePerson = (Person)personMock; //not working
Assert.AreEqual(1, 1);
}
I would like to assign mock variable of Person type to propeties of mock variable of type AddressBook.
Is this possible?
IAddressBook.SamplePerson property returns Person implementation and not IPerson interface, so your attempt to return IPerson will not work.
Either mock the Person class
var personMock = Substitute.For<Person>();
var addressBookMock = Substitute.For<IAddressBook>();
addressBookMock.SamplePerson.Returns(personMock);
or return an actual instance.
var person = new Person();
var addressBookMock = Substitute.For<IAddressBook>();
addressBookMock.SamplePerson.Returns(person);
So I have a list of objects (AllCompanies), and all the objects in the list inherit from the same class (Company). And I also have a field in the class they all inherit from which is another class entirely (Employees). I want to create a list of every Employee currently active, and I have every company in a list of objects. As you can see below I have tried to simply add the Employee's field to the list, but I get an error because I am trying to convert an object to a list of employees.
public class Main()
{
List<List<Employee>> AllEmployees = new List<List<Employee>>();
List<object> AllCompanies = new List<object>() { new SmallCompany(), new LargeCompany(), new SmallCompany() };
AllCompanies.ForEach(delegate(object o)
{
// - Here's the problem.
AllEmployees.Add(o.GetType().GetField("Employees").GetValue(o));
// - Here's the problem.
});
}
class Employee
{
public string Name;
public int Age;
public Employee(string name, int age)
{
Name = name;
Age = age;
}
}
class Company
{
public List<Employee> Employees = new List<Employee>();
}
class SmallCompany : Company
{
public SmallCompany(){}
}
class LargeCompany : Company
{
public LargeCompany(){}
}
How can I do this most efficiently?
You shouldn't type the list as a list of object types. The objects are all Company objects, and the list should reflect that.
List<Company> AllCompanies = new List<Company>()
{
new SmallCompany(),
new LargeCompany(),
new SmallCompany()
};
That will remove the need for any of that awful reflection code that will just make life hard.
Once you have that projecting each item into a new item given a selector is easy enough to do:
var allEmployees = AllCompanies.Select(company => company.Employees);
I don't know if i understood what you actually want, but if i did this would be, in my opinion, more understandable and easier solution:
class Program
{
static void Main(string[] args)
{
List<ICompany> AllCompanies = new List<ICompany>();
AllCompanies.Add(new Company());
AllCompanies.Add(new SmallCompany());
AllCompanies.Add(new LargeCompany());
List<Employee> AllEmployees = new List<Employee>();
foreach(var Company in AllCompanies)
{
Company.Employees.ForEach((Employee)=>
{
if(Employee.IsActive)
AllEmployees.Add(Employee);
});
}
}
}
class Employee
{
public string Name;
public int Age;
public bool IsActive;
public Employee(string name, int age)
{
Name = name;
Age = age;
}
}
interface ICompany
{
List<Employee> Employees { get; set; }
}
class Company: ICompany
{
public List<Employee> Employees { get; set; }
}
class SmallCompany : ICompany
{
public List<Employee> Employees { get; set; }
}
class LargeCompany : ICompany
{
public List<Employee> Employees { get; set; }
}
I have these classes:
public interface IPerson
{
string Name { get; set; }
}
public class Person : IPerson
{
public string Name { get; set; }
}
public interface IRoom
{
List<Furniture> Furnitures { get; set; }
List<Person> People { get; set; }
}
public class Room : IRoom
{
public List<Furniture> Furnitures { get; set; }
public List<Person> People { get; set; }
}
public enum Furniture
{
Table,
Chair
}
And I have this extension method:
public static void Assign<T>(this IRoom sender, Func<IRoom,ICollection<T>> property, T value)
{
// How do I actually add a Chair to the List<Furniture>?
}
And I want to use it like this:
var room = new Room();
room.Assign(x => x.Furnitures, Furniture.Chair);
room.Assign(x => x.People, new Person() { Name = "Joe" });
But I have no idea how to add T to ICollection<T>.
Trying to learn generics and delegates. I know room.Furnitures.Add(Furniture.Chair) works better :)
public static void Assign<T>(this IRoom room, Func<IRoom, ICollection<T>> collectionSelector, T itemToAdd)
{
collectionSelector(room).Add(itemToAdd);
}
You don't need a Func<IRoom,ICollection<T>> here. This takes room as argument and returns ICollection<T>. ICollection<T> as a parameter is enough. Let's rewrite your code as following to make it work.
public static void Assign<T>(this IRoom sender, ICollection<T> collection, T value)
{
collection.Add(value);
}
Then call it as
room.Assign(room.Furnitures, Furniture.Chair);
room.Assign(room.People, new Person() { Name = "Joe" });
If you're not satisfied with this approach and you need your own approach only then try the following
public static void Assign<T>(this IRoom sender, Func<IRoom, ICollection<T>> property, T value)
{
property(sender).Add(value);
}
Then call it with your own syntax should work
room.Assign(x => x.Furnitures, Furniture.Chair);
room.Assign(x => x.People, new Person() { Name = "Joe" });
Note:Keep in mind you've not initialized your collections, this will result in NullReferenceException, so to get rid of it add a contructor in your Room class as follows
public Room()
{
Furnitures = new List<Furniture>();
People = new List<Person>();
}
How can I instantiate the type T inside my InstantiateType<T> method below?
I'm getting the error: 'T' is a 'type parameter' but is used like a 'variable'.:
(SCROLL DOWN FOR REFACTORED ANSWER)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestGeneric33
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
Console.WriteLine(container.InstantiateType<Customer>("Jim", "Smith"));
Console.WriteLine(container.InstantiateType<Employee>("Joe", "Thompson"));
Console.ReadLine();
}
}
public class Container
{
public T InstantiateType<T>(string firstName, string lastName) where T : IPerson
{
T obj = T();
obj.FirstName(firstName);
obj.LastName(lastName);
return obj;
}
}
public interface IPerson
{
string FirstName { get; set; }
string LastName { get; set; }
}
public class Customer : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
}
public class Employee : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int EmployeeNumber { get; set; }
}
}
REFACTORED ANSWER:
Thanks for all the comments, they got me on the right track, this is what I wanted to do:
using System;
namespace TestGeneric33
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
Customer customer1 = container.InstantiateType<Customer>("Jim", "Smith");
Employee employee1 = container.InstantiateType<Employee>("Joe", "Thompson");
Console.WriteLine(PersonDisplayer.SimpleDisplay(customer1));
Console.WriteLine(PersonDisplayer.SimpleDisplay(employee1));
Console.ReadLine();
}
}
public class Container
{
public T InstantiateType<T>(string firstName, string lastName) where T : IPerson, new()
{
T obj = new T();
obj.FirstName = firstName;
obj.LastName = lastName;
return obj;
}
}
public interface IPerson
{
string FirstName { get; set; }
string LastName { get; set; }
}
public class PersonDisplayer
{
private IPerson _person;
public PersonDisplayer(IPerson person)
{
_person = person;
}
public string SimpleDisplay()
{
return String.Format("{1}, {0}", _person.FirstName, _person.LastName);
}
public static string SimpleDisplay(IPerson person)
{
PersonDisplayer personDisplayer = new PersonDisplayer(person);
return personDisplayer.SimpleDisplay();
}
}
public class Customer : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
}
public class Employee : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int EmployeeNumber { get; set; }
}
}
Declare your method like this:
public string InstantiateType<T>(string firstName, string lastName)
where T : IPerson, new()
Notice the additional constraint at the end. Then create a new instance in the method body:
T obj = new T();
Couple of ways.
Without specifying the type must have a constructor:
T obj = default(T); //which will produce null for reference types
With a constructor:
T obj = new T();
But this requires the clause:
where T : new()
To extend on the answers above, adding where T:new() constraint to a generic method will require T to have a public, parameterless constructor.
If you want to avoid that - and in a factory pattern you sometimes force the others to go through your factory method and not directly through the constructor - then the alternative is to use reflection (Activator.CreateInstance...) and keep the default constructor private. But this comes with a performance penalty, of course.
you want new T(), but you'll also need to add , new() to the where spec for the factory method
A bit old but for others looking for a solution, perhaps this could be of interest: http://daniel.wertheim.se/2011/12/29/c-generic-factory-with-support-for-private-constructors/
Two solutions. One using Activator and one using Compiled Lambdas.
//Person has private ctor
var person = Factory<Person>.Create(p => p.Name = "Daniel");
public static class Factory<T> where T : class
{
private static readonly Func<T> FactoryFn;
static Factory()
{
//FactoryFn = CreateUsingActivator();
FactoryFn = CreateUsingLambdas();
}
private static Func<T> CreateUsingActivator()
{
var type = typeof(T);
Func<T> f = () => Activator.CreateInstance(type, true) as T;
return f;
}
private static Func<T> CreateUsingLambdas()
{
var type = typeof(T);
var ctor = type.GetConstructor(
BindingFlags.Instance | BindingFlags.CreateInstance |
BindingFlags.NonPublic,
null, new Type[] { }, null);
var ctorExpression = Expression.New(ctor);
return Expression.Lambda<Func<T>>(ctorExpression).Compile();
}
public static T Create(Action<T> init)
{
var instance = FactoryFn();
init(instance);
return instance;
}
}
You can also use reflection to fetch the object's constructor and instantiate that way:
var c = typeof(T).GetConstructor();
T t = (T)c.Invoke();
Using a factory class to build your object with compiled lamba expression: The fastest way I've found to instantiate generic type.
public static class FactoryContructor<T>
{
private static readonly Func<T> New =
Expression.Lambda<Func<T>>(Expression.New(typeof (T))).Compile();
public static T Create()
{
return New();
}
}
Here is the steps I followed to set up the benchmark.
Create my benchmark test method:
static void Benchmark(Action action, int iterationCount, string text)
{
GC.Collect();
var sw = new Stopwatch();
action(); // Execute once before
sw.Start();
for (var i = 0; i <= iterationCount; i++)
{
action();
}
sw.Stop();
System.Console.WriteLine(text + ", Elapsed: {0}ms", sw.ElapsedMilliseconds);
}
I've also tried using a factory method:
public static T FactoryMethod<T>() where T : new()
{
return new T();
}
For the tests I've created the simplest class :
public class A { }
The script to test:
const int iterations = 1000000;
Benchmark(() => new A(), iterations, "new A()");
Benchmark(() => FactoryMethod<A>(), iterations, "FactoryMethod<A>()");
Benchmark(() => FactoryClass<A>.Create(), iterations, "FactoryClass<A>.Create()");
Benchmark(() => Activator.CreateInstance<A>(), iterations, "Activator.CreateInstance<A>()");
Benchmark(() => Activator.CreateInstance(typeof (A)), iterations, "Activator.CreateInstance(typeof (A))");
Results over 1 000 000 iterations:
new A(): 11ms
FactoryMethod A(): 275ms
FactoryClass A .Create(): 56ms
Activator.CreateInstance A (): 235ms
Activator.CreateInstance(typeof (A)): 157ms
Remarks: I've tested using both .NET Framework 4.5 and 4.6 (equivalent results).
Instead of creating a function to Instantiate the type
public T InstantiateType<T>(string firstName, string lastName) where T : IPerson, new()
{
T obj = new T();
obj.FirstName = firstName;
obj.LastName = lastName;
return obj;
}
you could have done it like this
T obj = new T { FirstName = firstName, LastName = lastname };