Given the interface
public interface baseInterface {
IList<double> listProperty { get; set; }
}
Is there any way to implement the interface with a property as a subclass of the property type as per the following example?
public class newClass : baseInterface
{
public List<double> listProperty { get; set; }
}
There are two approaches you could look at.
(1) You would have to use an explicit implementation to make it work:
public interface BaseInterface
{
IList<double> ListProperty { get; set; }
}
public class NewClass : BaseInterface
{
public List<double> ListProperty { get; set; }
IList<double> BaseInterface.ListProperty
{
get => this.ListProperty;
set => this.ListProperty = value.ToList();
}
}
(2) Use generics to allow for a subclass to be used:
public interface BaseInterface<L, T> where L : IList<T>
{
L ListProperty { get; set; }
}
public class NewClass : BaseInterface<List<double>, double>
{
public List<double> ListProperty { get; set; }
}
Both of these allow you to have a public List<double> ListProperty { get; set; } in NewClass.
You need to make interface generic.
public interface baseInterface <T> where T : IEnumerable<double>
{
T Data { get; set; }
}
public class derivedInterface : baseInterface <List<double>>
{
private List<double> m_Data = new List<double>();
public List<double> Data { get { return m_Data; }
set { this.m_MyData = value; }}
}
Related
I confused about a base interface property hiding, what is still needed in the implemented class, can somebody tell me why?
The goal will be the 'EndClass' only hide/override the 'IClassValue Value', and not need to implement the already hide 'IBaseClassValue Value'.
Thanks!
public interface IBaseClassValue { }
public interface IClassValue : IBaseClassValue { }
public class ClassValue : IClassValue { }
//-----------------------------------------
public interface IEndClassBase
{
IBaseClassValue Value { get; set; }
}
public interface IEndClassBaseChild : IEndClassBase
{
new IClassValue Value { get; set; }
}
//-----------------------------------------
public abstract class EndClassAbs<TValue>
{
TValue Value { get; set; }
}
public class EndClass : EndClassAbs<ClassValue>, IEndClassBaseChild
{
public new IClassValue Value { get; set; }
//IBaseClassValue IEndClassBase.Value { get; set; } //-> Why need here the base member while already hide in the 'IEndClassBaseChild' interface
}
If I use somekind of shadow class '_EndClass' then inherit from it, the 'EndClass' could hide/override the 'ClassValue'. I still don't know why this can not do in one step.
public class _EndClass : EndClassAbs<ClassValue>, IEndClassBase
{
public new IBaseClassValue Value { get; set; }
}
public class EndClass : _EndClass, IEndClassBaseChild
{
public new IClassValue Value { get; set; }
}
I have an interface (Ae) that has a list of objects (List) from another interface (Ba).
I have a class that implements interface Ae.
I have several classes that implement the Ba interface.
Is there any way to make each class that implements interface Ae has a List of one of the concrete classes that implement Ba as property?
public interface IQuestion
{
IAnswerOption[] Answers { get; set; }
}
public interface IAnswerOption
{
int Id { get; }
bool IsCorrect { get; set; }
}
public class AnswerOptionText : IAnswerOption
{
public int Id { get; }
public bool isCorrect;
public string ansText;
}
public class AnswerOptionImage : IAnswerOption
{
public int Id { get; }
public bool isCorrect;
public string imgSlug;
}
public class AudioQuestion : IQuestion
{
public AnswerOptionImage[] Answers;
public string audioName;
}
public class TextQuestion : IQuestion
{
public AnswerOptionText[] Answers { get; set; }
public string questionText { get; set; }
}
When I try it, AudioQuestion and TextQuestion doesn't allow me to use AnswerOptionImage[] and AnswerOptionText[] respectively.
Visual Studio says that I need to implement interface member IQuestion.Answers, but this is not what I intend.
If someone can help me I would be very grateful. Thanks.
It seems that using generics for your IQuestion interface will be a good fit:
public interface IQuestion<T> where T: IAnswerOption
{
T[] Answers { get; set; }
}
public class AudioQuestion : IQuestion<AnswerOptionImage>
{
public AnswerOptionImage[] Answers{ get; set; }
public string audioName;
}
public class TextQuestion : IQuestion<AnswerOptionText>
{
public AnswerOptionText[] Answers { get; set; }
public string questionText { get; set; }
}
I have a Json class "GetAllDevices()". My JSON response consists of an Array/List of objects, where each object has the below common properties.
public class GetAllDevices
{
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("actions")]
public Action[] Actions { get; set; }
public class Action
{
public string _id { get; set; }
public Action_Def action_def { get; set; }
}
public class Action_Def
{
public string _id { get; set; }
public string name { get; set; }
}
}
I want to create 2 generic lists containing all the above properties based on its "type".
lstfoo1 List contains all the properties(_id, name type and actions) where type="foo1". Similarly, lstfoo2 is a List which contains the above properties where type="foo2".
What I have done so far:
string strJson=getJSON();
Foo1 lstfoo1=new Foo1();
Foo2 lstfoo2=new Foo2();
List<Foo1> foo1list= lstfoo1.GetDeviceData(strJson);
List<Foo2> foo2list = lstfoo2.GetDeviceData(strJson);
public class AllFoo1: GetAllDevices
{
}
public class AllFoo2: GetAllDevices
{
}
public abstract class HomeDevices<T>
{
public string type { get; set; }
public string _id { get; set; }
public List<AllFoo1> lstfoo1{ get; set; }
public List<AllFoo2> lstfoo2{ get; set; }
public abstract List<T> GetDeviceData(string jsonResult);
}
public class Foo1: HomeDevices<AllFoo1>
{
public Foo1()
{
type = "foo1";
}
public override List<AllFoo1> GetDeviceData(string jsonResult)
{
var lst =Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo1>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
public class Foo2: HomeDevices<AllFoo2>
{
public Foo2()
{
type = "foo2";
}
public override List<AllFoo2> GetDeviceData(string jsonResult)
{
var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo2>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
My question is, is there an easier way to do this using abstract classes? Can I directly convert my "GetAllDevices" class into an abstract class and inherit it and deserialize into it and create a generic list?
This should help, if I understand your problem correctly. Let me know if you have questions or it doesn't work as you need. I put this together really quickly without testing.
The way the Type property is defined could be improved but I left it as you had it.
public class MyApplication
{
public void DoWork()
{
string json = getJSON();
DeviceTypeOne foo1 = new DeviceTypeOne();
DeviceTypeTwo foo2 = new DeviceTypeTwo();
IList<DeviceTypeOne> foo1Results = foo1.GetDeviceData(json); // calls GetDeviceData extension method
IList<DeviceTypeTwo> foo2Results = foo2.GetDeviceData(json); // calls GetDeviceData extension method
}
}
// implemented GetDeviceData as extension method of DeviceBase, instead of the abstract method within DeviceBase,
// it's slightly cleaner than the abstract method
public static class DeviceExtensions
{
public static IList<T> GetDeviceData<T>(this T device, string jsonResult) where T : DeviceBase
{
IEnumerable<T> deviceDataList = JsonConvert.DeserializeObject<IEnumerable<T>>(jsonResult);
IEnumerable<T> resultList = deviceDataList.Where(x => x.Type.Equals(typeof(T).Name));
return resultList.ToList();
}
}
// abstract base class only used to house common properties and control Type assignment
public abstract class DeviceBase : IDeviceData
{
protected DeviceBase(string type)
{
if(string.IsNullOrEmpty(type)) { throw new ArgumentNullException(nameof(type));}
Type = type; // type's value can only be set by classes that inherit and must be set at construction time
}
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; private set;}
[JsonProperty("actions")]
public DeviceAction[] Actions { get; set; }
}
public class DeviceTypeOne : DeviceBase
{
public DeviceTypeOne() : base(nameof(DeviceTypeOne))
{
}
}
public class DeviceTypeTwo : DeviceBase
{
public DeviceTypeTwo() : base(nameof(DeviceTypeTwo))
{
}
}
// implemented GetAllDevices class as IDeviceData interface
public interface IDeviceData
{
string Id { get; set; }
string Name { get; set; }
string Type { get; }
DeviceAction[] Actions { get; set; }
}
// renamed and relocated class Action to DeviceAction
public class DeviceAction
{
public string Id { get; set; }
public DeviceActionDefinition DeviceActionDefinition { get; set; }
}
// renamed and relocated Action_Def to DeviceActionDefinition
public class DeviceActionDefinition
{
public string Id { get; set; }
public string Name { get; set; }
}
It should be simple enough to move the implementation of method GetDeviceData() to the base class.
For this to work, you will need to add a constraint on T so the compiler knows a bit more about the base type. You will also need to implement a constructor to populate the concrete type's type string you use around. This is a necessary measure to ensure the value is always populated as it is used for comparison in the method in question:
public abstract class HomeDevices<T> where T: GetAllDevices
{
public HomeDevices(string concreteType)
{
type = concreteType;
}
public string type { get; set; }
public string _id { get; set; }
public List<AllFoo1> lstfoo1 { get; set; }
public List<AllFoo2> lstfoo2 { get; set; }
//This method is now generic and works for both.
public List<T> GetDeviceData(string jsonResult)
{
var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
I hope that helps.
I have following code below. I have two main interfaces IWatch and IWatchService. Oryginally Watch() was in IWatchService and there was no IWatch but since that CollectionService cannot use Watch() method i decided (ISP) to create IWatch interface additionally.In CollectionService i want in ctor pass either DatabaseWatchService or RemoteFilesWatchService therefore i put parameter type in ctor as IWatchService<IEntity> watchService nevertheless when in DoIt() method initialize fileWatcherServiceCsv variable it says:
Cannot implicitly convert type 'RemoteFilesWatchService' to
'IWatchService'. An explicit conversion exists (are you
missing a cast?)
public interface IWatch
{
void Watch();
}
public interface IWatchService<TDataEntity> where TDataEntity : IEntity
{
INotificationFactory NotificationFactory { get; }
ObservableCollection<TDataEntity> MatchingEntries { get; set; }
}
public interface IDatabaseWatchService<TDataEntity> : IWatchService<TDataEntity> where TDataEntity : IDatabaseEntity
{
IDatabaseRepository<IDbManager> DatabaseRepository { get; }
}
public interface IRemoteFilesWatchService<TDataEntity> : IWatchService<TDataEntity> where TDataEntity : IFileEntity
{
List<string> ExistingRemoteFiles { get; set; }
List<RemoteLocation> RemoteLocations { get; set; }
IWinScpOperations RemoteManager { get; set; }
IRemoteFilesRepository<IDbManager, TDataEntity> RemoteFilesRepository { get; }
}
public class RemoteFilesWatchService : IRemoteFilesWatchService<IFileEntity>, IWatch
{
public INotificationFactory NotificationFactory { get; }
public ObservableCollection<IFileEntity> MatchingEntries { get; set; }
public List<string> ExistingRemoteFiles { get; set; }
public List<RemoteLocation> RemoteLocations { get; set; }
public IWinScpOperations RemoteManager { get; set; }
public IRemoteFilesRepository<IDbManager, IFileEntity> RemoteFilesRepository { get; }
public RemoteFilesWatchService(IWinScpOperations remoteOperator,
IRemoteFilesRepository<IDbManager, IFileEntity> remoteFilesRepository,
INotificationFactory notificationFactory)
{
RemoteManager = remoteOperator;
RemoteFilesRepository = remoteFilesRepository; //csv, xml or other repo could be injected
NotificationFactory = notificationFactory;
}
public void Watch()
{
}
}
public class DatabaseWatchService : IDatabaseWatchService<DatabaseQuery>, IWatch
{
public INotificationFactory NotificationFactory { get; }
public ObservableCollection<DatabaseQuery> MatchingEntries { get; set; }
public IDatabaseRepository<IDbManager> DatabaseRepository { get; }
public DatabaseWatchService(IDatabaseRepository<IDbManager> databaseRepository,
INotificationFactory notificationFactory)
{
DatabaseRepository = databaseRepository;
NotificationFactory = notificationFactory;
}
public void Watch()
{
}
}
public class CollectionService
{
private IWatchService<IEntity> _watchService;
public CollectionService(IWatchService<IEntity> watchService)
{
_watchService = watchService;
}
}
class Run
{
void DoIt()
{
IWatchService<IEntity> fileWatcherServiceCsv = new RemoteFilesWatchService(new WinScpOperations(),
new RemoteCsvFilesRepository(new DbManager(ConnectionDbType.MySql)),
new NotificationFactory());
var coll1 = new CollectionService(fileWatcherServiceCsv);
}
}
public interface IEntity
{
}
public interface IFileEntity : IEntity
{
int Id { get; set; }
string Name { get; set; }
bool IsActive { get; set; }
bool RemoveFromSource { get; set; }
string DestinationFolder { get; set; }
RemoteLocation RemoteLocation { get; set; }
}
public interface IDatabaseEntity : IEntity
{
}
public class CsvFile : IFileEntity
{
public int ColumnHeader { get; set; }
public int ColumnsCount { get; set; }
public string Separator { get; set; }
public int ValuesRowStartposition { get; set; }
public int ColumnRowPosition { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public bool RemoveFromSource { get; set; }
public string DestinationFolder { get; set; }
public RemoteLocation RemoteLocation { get; set; }
}
public class XmlFile : IFileEntity
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public bool RemoveFromSource { get; set; }
public string DestinationFolder { get; set; }
public RemoteLocation RemoteLocation { get; set; }
public string SubNode { get; set; }
public string MainNode { get; set; }
}
This question gets posted almost every day. One more time!
A box of apples is not a box of fruit. Why not?
You can put a banana into a box of fruit, but you cannot put a banana into a box of apples, so a box of apples is not a box of fruit, because the operations you can perform on them are different. Similarly, a box of fruit is not a box of apples.
You're trying to use a IWatchService (box) of IFileEntity (apples) as an IWatchService of IEntity (fruit), and that's not legal.
Now, you might notice that in C# you can use an IEnumerable<Apple> where an IEnumerable<Fruit> is expected. That works just fine because there is no way to put a banana into an IEnumerable<Fruit>. In every member of IEnumerable<T> and IEnumerator<T>, the T comes out, not in.
If you are in that situation then you can mark your interface as
interface IWatchService<out T> ...
And the compiler will verify that every T in the interface is used in "out" positions, and then will allow the conversion you want.
That conversion is called a generic covariant conversion and it only works when:
The generic type is an interface or delegate
The type parameter is marked out, and the compiler verifies that is safe
The varying types (Fruit and Apple, say) are both reference types. You can't do covariant conversions involving int and object, for example.
Your RemoteFilesWatchService implements interface IWatchService<IFileEntity>, while your CollectionService expects a IWatchService<IEntity>. The two types are different, that's why it cannot convert.
Modify your CollectionService to accept IWatchService<IFileEntity> instead, or make RemoteFilesWatchService implement IRemoteFilesWatchService<IEntity>. Or use a non-generic interface in CollectionService instead.
You cannot have a IWatchService<IFileEntity> and treat it as a IWatchService<IEntity>. Compare it to a List<T> for example. You cannot expect to be able to do this:
class Animal {}
class Bird : Animal {}
class Elephant : Animal {}
var birds = new List<Bird>();
// compiler does not allow this...
List<Animal> animals = birds;
// ...because there is no point in adding elephants to a list of birds.
animals.Add(new Elephant());
Making a slight change to take support from variance, should fix your issue as follows:
public interface IEntity
{
}
public interface IFileEntity : IEntity
{
...
}
public interface IWatchService<out TDataEntity> where TDataEntity : IEntity //note the "out" keyword here.
{
}
You can learn more about Variance in Generic Interfaces Here
I have following original class structure:
public interface IMapFromElement
{
string Prop { get; }
}
public interface IMapFromElementDerived : IMapFromElement
{
string Prop2 { get; }
}
public interface IMapFromElement2 : IMapFromElement
{
}
public interface IMapFromElementDerived2 : IMapFromElementDerived, IMapFromElement2
{
}
public abstract class MapFromElement : IMapFromElement2
{
public string Prop { get; set; }
}
public class MapFromElementDerived : MapFromElement, IMapFromElementDerived2
{
public string Prop2 { get; set; }
}
I'm trying to map them to:
public class MapTo
{
public IMapToElementWritable Element { get; set; }
}
public interface IMapToElementWritable : IMapFromElement
{
new string Prop { get; set; }
}
public interface IMapToElementWritableDerived : IMapFromElementDerived, IMapToElementWritable
{
new string Prop2 { get; set; }
}
public abstract class MapToElement : IMapToElementWritable
{
public string Prop { get; set; }
}
public class MapToElementDerived : MapToElement, IMapToElementWritableDerived
{
public string Prop2 { get; set; }
}
I try to map them with:
var from = new MapFrom
{
Element = new MapFromElementDerived {Prop = "qwerty", Prop2 = "asdf"}
};
Mapper.Initialize(
cfg =>
{
cfg.CreateMap<IMapFrom, MapTo>();
cfg.CreateMap<IMapFromElement, IMapToElementWritable>();
cfg.CreateMap<IMapFromElementDerived, IMapToElementWritableDerived>()
.IncludeBase<IMapFromElement, IMapToElementWritable>()
.ConstructUsing((ResolutionContext item) => new MapToElementDerived());
cfg.Seal();
});
Mapper.AssertConfigurationIsValid();
var result = Mapper.Map<MapTo>(from);
I expected, that I will have as output MapTo with MapToElementDerived as it's Element property value. But really I was unable to achieve it - Automapper creates proxy for IMapToElementWritable instead. Looks like IncludeBase doesn't work (I tried it with Include also, but it haven't helped). Maybe I just write incorrect config.
Looks like there is an issue in Automapper. I've tried to resolve it in https://github.com/AutoMapper/AutoMapper/pull/1037