I am trying to make a function that works with a list of an interface but I would like to keep the concrete class values for those lists. For example:
public interface GUID_OBJECT
{
string GUID { get; set; }
}
public class Car : GUID_OBJECT
{
public string GUID { get; set; }
public string CarSpecifikProp { get; set; }
}
public class Bike : GUID_OBJECT
{
public string GUID { get; set; }
public string BikeSpecifikProp { get; set; }
}
class Program
{
static void Main(string[] args)
{
var cars = new List<Car>() { new Car() { GUID = "1", CarSpecifikProp = "carstuff" }, new Car() { GUID = "2", CarSpecifikProp = "carsuff" } };
var bikes = new List<Bike>() { new Bike() { GUID = "1", BikeSpecifikProp = "bikestuff" }, new Bike() { GUID = "2", BikeSpecifikProp = "bikestuff" } };
var filteredCars = FilterGuidObjects(cars);
foreach (var car in filteredCars)
{
car.CarSpecifikProp = "changethis";
}
var filteredBikes = FilterGuidObjects(bikes);
foreach (var bike in filteredBikes)
{
bike.BikeSpecifikProp = "changethis";
}
Console.ReadKey();
}
static List<GUID_OBJECT> FilterGuidObjects(List<GUID_OBJECT> objects)
{
return objects.Where(x => x.GUID == "1").ToList();
}
}
This code doesn't work but it illustrates what I would like to do. I have a web api project that returns various type of lists of objects, but all these objects have some things in common such as GUID for example. Can I write functions that work with the interface GUID_OBJECT but keep the Car and Bike specific properties after that function returns its List of GUID_OBJECT interfaces? How would you deal with a scenario like this?
make a generic method with a constraint:
static List<G> FilterGuidObjects<G>(List<G> objects) where G: GUID_OBJECT
{
return objects.Where(x => x.GUID == "1").ToList();
}
The point of interfaces is to have only the common properties of the classes that implement them. If you need to use a specific property you'll need to cast to the type you want:
var obj = (MyType) myInterface
Since you're working with lists, you can cast the entire list like this:
listOfInterface.Cast<MyType>().ToList()
Consider implementing FilterGuidObjects as a generic function:
static List<T> FilterGuidObjects<T>(List<T> objects) where T : GUID_OBJECT
{
return objects.Where(x => x.GUID == "1").ToList();
}
there are many ways of achieving this but the crux of the matter is you have to convert the interface back to the original type
Method 1: generic filter on the function
static List<T> FilterGuidObjects(List<T> objects)
:where T:GUID_OBJECT
{
return objects.Where(x => x.GUID == "1").ToList();
}
Pros Quick and simple, will even infer the type automatically
Cons you can't feed in a Mixed list
Method 2 Type Filter the collection
var filteredCars = FilterGuidObjects(MixedListOfVechiles).OfType<Car>();
Pros Can handle mixed lists
Con have to specify the conversion every time
Method 3 Convert the Type Directly
var car = guid_object as Car
if(car != null)
car.CarSpecifikProp = "changethis";
or
if(guid_object is Car)
{
var car = (Car)guid_object
car.CarSpecifikProp = "changethis";
}
Pros doesn't use generics
Con requires lots of code
Related
I've seen a few questions like this floating around but I'm looking for a good explination of how to get around this. I understand that Moq can't mock the extension call, but I'm just looking for a really good example. In the current code I there is a call like
var thing = listOfthings.myList.SingleOrDefault(lt => lt.Name== "NameToFind");
I've tried
MockedlistOfThings.Setup(x => x.myList.SingleOrDefault(o => o.Name == "NameToFind")).Returns(fakeObject);
Just looking for a good work around. thanks.
To further elaborate on how this situation came up, we are currently running a translation engine against large sets of data, that has to be run line by line. This translation engine passes in an Interface called IListOfthings. listOfthings is actually holding reference data in a dictionary that is preloaded in another call higher up in the program. I have created a "fakeObject" <- dictionary that holds my fake data that the method can use. I have Mocked the IlistOfthings which is passed in to the calling method. but I don't see how to fake the SingleOrDefault call.
Simplifed method below.
Public class ClassIMTesting
{
public void Translate(myObject obj, IlistOfThings listOfthings){
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
//Other logic here .....
}
}
public class Thing()
{
public string Name { get; set; }
public Dictionary MyDict { get; set; }
}
[TestFixture()]
public class MyCodeTest
{
MyObject myObj;
Mock<IListOfthings> listOfThings;
Thing thing;
[SetUp]
public void Setup()
{
myObj = new MyObject();
_thing = new thing();
_thing.Name = "MyName";
var myDict = new Dictionary<string, string>();
myDict.Add("70,~", "");
myDict.Add("70,145", "expectedResult");
myDict.Add("911,", "expectedResult");
thing.MyDict = myDict;
listOfThings = new Mock<IListOfthings>();
listOfThings.Setup(x => x.MyList.SingleOrDefault(o => o.Name == "MyName")).Returns(thing);
}
[TestCase("70", "~", "70070")]
[TestCase("70", "145", "expectedResult")]
[TestCase("911", "", "expectedResult")]
public void TranslateTest(string iTC, string ITCode, string expectedResult)
{
myObject.ITC = iTC;
myObject.ITCode = iTCode;
ClassIMTesting p = new ClassIMTesting();
p.Translate(myObject, listofThings.Object);
Assert.That(myObject.ITC3Code, Is.EqualTo(expectedResult));
}
}
public interface IListOfThings
{
List<Thing> MyList{ get; set; }
}
Given
public interface IListOfThings {
List<Thing> MyList { get; set; }
}
public class Thing() {
public string Name { get; set; }
public Dictionary MyDict { get; set; }
}
In order to provide a mock to satisfy the following example
public class ClassImTesting {
public Thing Translate(IlistOfThings listOfthings){
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
return thing
}
}
The mock just needs to return a collection that will allow the SingleOrDefault extension to behave as expected when invoked.
For example
//Arrrange
Mock<IListOfthings> listOfThings = new Mock<IListOfthings>();
var thing = new Thing {
Name = "NameToFind",
//...
};
List<Thing> list = new List<Thing>() { thing };
listOfThings.Setup(_ => _.MyList).Returns(list);
var subject = new ClassImTesting();
//Act
var actual = subject.Translate(listOfThings.Object);
//Assert
Assert.That(actual, Is.EqualTo(thing));
By having the mock return an actual List<Thing>, when
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
is invoked, the SingleOrDefault extension acts on a list where I can behave as expected.
I'm trying to understand the resultant type from a LINQ select action. I'm having trouble understanding how to utilize the result.
Consider the following:
public class ReportContract
{
public int ContractId { get; set; }
public string ContractName { get; set; }
public string Title { get; set; }
public string[] Details { get; set; }
}
public class ReportContractVM
{
public int ContactId { get; set; }
public string ContractName { get; set; }
}
public class SomeController : ControllerBase
{
public ActionResult<IEnumerable<ReportContractVM>> Get()
{
IEnumerable<ReportContract> contracts = CreateConrtacts();
IEnumerable<ReportContractVM> result = contracts.Select(
x => new ReportContractVM
{
ContactId = x.ContractId,
ContractName = x.ContractName
}
);
return Ok(result);
}
private IEnumerable<ReportContract> CreateContracts()
{
List<ReportContract> contracts = new List<ReportContract>()
{
new ReportContract {
ContractId = 1234,
ContractName= "ABCD",
Details= new string[] {
"test", "Best", "rest", "jest"},
Title="First"
},
new ReportContract {
ContractId = 1235,
ContractName= "EFGH",
Details= new string[] {
"fish", "dish", "wish", "pish"},
Title="Second"
},
new ReportContract {
ContractId = 1236,
ContractName= "IJKL",
Details= new string[] {
"hot", "tot", "mot", "jot"},
Title="Third"
},
new ReportContract {
ContractId = 1237,
ContractName= "MNOP",
Details= new string[] {
"ring", "sing", "bing", "ping"},
Title="Fourth"
}
};
return contracts;
}
}
Inspecting the type assigned to 'result' in the debugger yields:
System.Linq.Enumberable.SelectListIterator
<
ComplexIEnumerable.ReportContract,
ComplexIEnumerable.ReportContractVM
>
I am not sure how this relates to
IEnumerable<ReportContractVM>.
How is
IEnumerable<ReportContractVM>
accessed from this result?
Please ignore the rest of this text. The "intelligent" editor is demanding more detail and I think this suffices.
I recommend reading this article that explains what Enumerator (aka yield return methods) materialization is - as it's core to how Linq works and how to use IEnumerable<T> results (note that an IEnumerable<T> can refer to a both materialized collections like T[] or List<T> and also non-materialized enumerators):
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/intermediate-materialization
As for your case, generally speaking, never return a non-materialized Entity Framework (i.e. database-backed) IEnumerable<T> or IQueryable<T> from an ASP.NET Web API Controller or pass a non-materialized IEnumerable<T> as a member of a ViewModel (this is because the lifetime of the parent DbContext may be shorter than the lifetime of the IEnumerable<T>/IQueryable<T> object). However returning an non-materialized collection using only in-memory objects is fine (such as an enumerator over enum values to get SelectListItem objects):
Specifically, change this:
IEnumerable<ReportContractVM> result = contracts.Select(
x => new ReportContractVM
{
ContactId = x.ContractId,
ContractName = x.ContractName
}
);
to this:
List<ReportContractVM> list = contracts
.Select( x => new ReportContractVM { ContractId = x.ContractId, ContractName = x.ContractName } )
.ToList();
Also, change your ActionResult<T> to use IReadOnlyList<T> instead of IEnumerable<T> which will help ensure you always return a materialized list instead of a possibly non-materialized enumerator:
public class SomeController : ControllerBase
{
public ActionResult<IReadOnlyList<ReportContractVM>> Get()
{
}
}
BTW, I've been having problems with ActionResult<T> not working well with generics and in async Task<ActionResult<T>> actions so I personally prefer to do this, but YMMV:
public class SomeController : ControllerBase
{
[Produces( typeof( IReadOnlyList<ReportContractVM> ) )
public IActionResult Get()
{
}
// if async:
[Produces( typeof( IReadOnlyList<ReportContractVM> ) )
public async Task<IActionResult> Get()
{
}
}
Basically the output is the concrete enumerable type returned from Select with type parameters referencing both the input and output types. It may be easier to see in a simplified example below.
namespace ExampleNamespace
{
class A
{
public A(int i) { }
}
}
Now say I have this code somewhere:
List<int> i = new List<int>() { 1, 2, 3, 4, 5, 6 };
var temp = i.Select(x => new A(x));
Upon inspection the type of temp is:
System.Linq.Enumerable.WhereSelectListIterator<int, ExampleNamespace.A>
So to break this down:
System.Linq.Enumerable.WhereSelectListIterator is the type of iterator returned from Select. This differs from your type slightly probably due to different .NET versions.
int is the the type that your starting IEnumerable held
ExampleNamespace.A is the full name of the output type.
That all being said, you should read and understand what Dai posted in their answer.
I'm trying to create a method which can be used like this:
Assembler.CreateTransfer(i);
i is an item inside a dynamic collection.
i is a domain object.
CreateTransfer() should return an instance of i type + Transfer (if my domain object is User, then it should return an instance of UserTransfer.
As for my models is like this:
public abstract class UserBase {
public long UserId { get; set; }
public string Username { get; set; }
}
public class UserTransfer : UserBase, ITransferObject { }
public partial class User : UserTransfer, IModelBase, IDomainObject {
public User() {
Roles = new List<Role>();
}
public virtual ICollection<Role> Roles { get; set; }
}
So far, I've accomplished this:
public static TTransfer CreateTransfer<TTransfer, TDomain>(TDomain d)
where TTransfer : ITransferObject
where TDomain : IDomainObject
{ ... }
This works, because I know the type of TTransfer and TDomain.
And I can call it like: CreateTransfer<UserTransfer, User>(d).
The problem comes when I try create the dto without specifying any type:
CreateTransfer(d);
Of course I've added an overload for this task and I hope I can magically accomplish the following:
public static ITransferObject CreateTransfer(IDomainObject d) {
// do magic
return CreateTransfer<transfer, domain>(d);
}
But in the real world, this is as far as I could get:
public static ITransferObject CreateTransfer(IDomainObject d) {
var dType = d.GetType();
var assemblyName = dType.Assembly.FullName;
var domainName = dType.FullName;
var transferName = domainName + "Transfer";
var domain = Activator.CreateInstance(assemblyName, domainName).UnWrap();
var transfer = Activator.CreateInstance(assemblyName, transferName).UnWrap();
return CreateTransfer< ?, ?>(d); // Problem
}
Both domain and transfer objects are being created correctly.
The main question is: Is there any way to be able to call CreateTransfer<domain, transfer>(d)? Any help will be appreciated.
You can use reflection to call the generic method.
Something like this:
var method = typeof(ClassThatDefinesCreateTransfer)
.GetMethods()
.Single(x => x.Name == "CreateTransfer" &&
x.IsGenericMethodDefinition)
.MakeGenericMethod(dType, transferType);
return (ITransferObject )method.Invoke(null, new object[] { d });
You probably want to cache at least the result of typeof(ClassThatDefinesCreateTransfer).GetMethods().
I have a (string, object) dictionary, object (class) has some values including data type which is defined by enum. I need a GetItemValue method that should return dictionary item's value. So return type must be the type which is defined in item object.
Class Item
{
String Name;
DataValueType DataType;
Object DataValue;
}
private Dictionary<string, Item> ItemList = new Dictionary<string, Item>();
void Main()
{
int value;
ItemList.Add("IntItem", new Item("IntItem", DataValueType.TInt, 123));
value = GetItemValue("IntItem"); // value = 123
}
What kind of solution can overcome this problem?
Best Regards,
You can use Generic Classes
Class Item<T>
{
String Name;
T DataTypeObject;
Object DataValue;
public T GetItemValue()
{
//Your code
return DataTypeObject;
}
}
A better solution would be to introduce an interface that you make all the classes implement. Note that the interface doesn't necessarily have to specify any behavior:
public interface ICanBePutInTheSpecialDictionary {
}
public class ItemTypeA : ICanBePutInTheSpecialDictionary {
// code for the first type
}
public class ItemTypeB : ICanBePutInTheSpecialDictionary {
// code for the second type
}
// etc for all the types you want to put in the dictionary
To put stuff in the dictionary:
var dict = new Dictionary<string, ICanBePutInTheSpecialDictionary>();
dict.add("typeA", new ItemTypeA());
dict.add("typeB", new ItemTypeB());
When you need to cast the objects to their specific types, you can either use an if-elseif-block, something like
var obj = dict["typeA"];
if (obj is ItemTypeA) {
var a = obj as ItemTypeA;
// Do stuff with an ItemTypeA.
// You probably want to call a separate method for this.
} elseif (obj is ItemTypeB) {
// do stuff with an ItemTypeB
}
or use reflection. Depending on how many choices you have, either might be preferrable.
If you have a 'mixed bag' you could do something like this...
class Item<T>
{
public String Name { get; set; }
public DataValueType DataType { get; set; }
public T DataValue { get; set; }
}
class ItemRepository
{
private Dictionary<string, object> ItemList = new Dictionary<string, object>();
public void Add<T>(Item<T> item) { ItemList[item.Name] = item; }
public T GetItemValue<T>(string key)
{
var item = ItemList[key] as Item<T>;
return item != null ? item.DataValue : default(T);
}
}
and use it like...
var repository = new ItemRepository();
int value;
repository.Add(new Item<int> { Name = "IntItem", DataType = DataValueType.TInt, DataValue = 123 });
value = repository.GetItemValue<int>("IntItem");
If you have just a couple types - you're better off with Repository<T>.
I found a solution exactly what I want. Thanks to uncle Google.
Thanks all of you for your kind interest.
public dynamic GetValue(string name)
{
if (OpcDataList[name].IsChanged)
{
OpcReflectItem tmpItem = OpcDataList[name];
tmpItem.IsChanged = false;
OpcDataList[name] = tmpItem;
}
return Convert.ChangeType(OpcDataList[name].ItemValue.Value, OpcDataList[name].DataType);
}
How do I find and replace a property using Linq in this specific scenario below:
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
//TODO: Just copying values... Find out how to find the index and replace the value
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
Thanks for helping out in advance.
Do not use LINQ because it will not improve the code because LINQ is designed to query collection and not to modify them. I suggest the following.
// Just realized that Array.IndexOf() is a static method unlike
// List.IndexOf() that is an instance method.
Int32 index = Array.IndexOf(this.Properties, name);
if (index != -1)
{
this.Properties[index] = value;
}
else
{
throw new ArgumentOutOfRangeException();
}
Why are Array.Sort() and Array.IndexOf() methods static?
Further I suggest not to use an array. Consider using IDictionary<String, Property>. This simplifies the code to the following.
this.Properties[name] = value;
Note that neither solution is thread safe.
An ad hoc LINQ solution - you see, you should not use it because the whole array will be replaced with a new one.
this.Properties = Enumerable.Union(
this.Properties.Where(p => p.Name != name),
Enumerable.Repeat(value, 1)).
ToArray();
[note: this answer was due to a misunderstanding of the question - see the comments on this answer. Apparently, I'm a little dense :(]
Is your 'Property' a class or a struct?
This test passes for me:
public class Property
{
public string Name { get; set; }
public string Value { get; set; }
}
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
[TestMethod]
public void TestMethod1()
{
var pb = new PropertyBag() { Properties = new Property[] { new Property { Name = "X", Value = "Y" } } };
Assert.AreEqual("Y", pb["X"].Value);
pb["X"] = new Property { Name = "X", Value = "Z" };
Assert.AreEqual("Z", pb["X"].Value);
}
I have to wonder why the getter returns a 'Property' instead of whatever datatype .Value, but I'm still curious why you're seeing a different result than what I am.