Is there any possibility to create an interface in order to require a virtual collection type in my class?
Regards
namespace Models.Entities
{
public partial class FileType : IMyInterface
{
public long CompanyId { get; set; }
public long FileTypeId { get; set; }
public string AcceptType { get; set; }
//IMyInterface contract
public virtual ICollection<Translation> FileTypeTranslations { get; set; }
public FileType()
{
this.FileTypeTranslations = new HashSet<FileTypeTranslation>();
}
}
public class Translation : EntityTranslation<long, FileType>
{
[Required]
public string TypeName { get; set; }
}
}
No. virtual is an implementation detail not a contract (ie. interface) detail.
The virtual keyword is used to modify a method, property, indexer, or event declaration and allow for it to be overridden in a derived class.
I marked the key part of that description from the documentation in bold
You can try to use abstract class instead of interface. So at classes, inherited from FileType, you can override this property again, i.e. behavior like with virtual access modifier at FileType declaration:
public abstract class MyInterface
{
public abstract ICollection<Translation> FileTypeTranslations { get; set; }
}
public class FileType : MyInterface
{
public override ICollection<Translation> FileTypeTranslations { get; set; }
}
public class FileTypeInherited : FileType
{
public override ICollection<Translation> FileTypeTranslations { get; set; }
}
In order to override method, property, event, indexer they must be virtual. But if they are virtual its not mandatory to override them its optional. and if we talk about abstract classes the member of abstract class is virtual implicitly. That's why we need to use override keyword when defining them in some subclass.
Related
I have a base class that has an abstract property:
public class BottomClass {
public abstract string Name {get;set;}
}
I now have a class that derives from that:
public class MiddleClass:BottomClass {
public override string Name {get;set;}
}
what I now want is that the "MiddleClass" itself defines that property as abstract so that a class deriving from that will be forced to implement the property. The following code is not working that way:
public class MiddleClass:BottomClass {
public abstract override string Name {get;set;} // Not possible that way
}
public class TopClass:MiddleClass {
public override string Name {get;set;} ="tothetop";
}
Is there a way to achieve what I want?
If you define a property as abstract, you have to implement it in some non abstract class. So the only possible way to have the property in both classes is
public abstract class BottomClass
{
public abstract string NameB { get; set; }
}
public abstract class MiddleClass : BottomClass
{
public abstract string NameM { get; set; }
}
public class TopClass : MiddleClass {
public override string NameB { get; set; }
public override string NameM { get; set; }
}
As far as I can understand, your intention is to have 'Name' property in MiddleClass.
Or don't implement it, as Damien commented above.
Throw exceptions if you have some reason not to make the class abstract.
public class MiddleClass:BottomClass
{
public override string Name
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
}
Say I have a class like...
public abstract class Base
{
public abstract IAttributes Attributes{ get; set; }
}
public interface IAttributes
{
string GlobalId { get; set; }
}
And a class like this...
public class ImplementAttributes : IAttributes
{
public string GlobalId { get; set; } = "";
public string LocalId { get; set; } = "";
// Other Properties and Methods....
}
And then I implement it like...
public class Derived: Base
{
public new ImplementAttributes Attributes { get; set; }
}
Now, I realise the above will not work because I can't override the property Attributes and if I hide it with new then the following bellow is null because the Base property does not get written.
public void DoSomethingWithAttributes(Base base)
{
var Foo = FindFoo(base.Attributes.GlobalId); // Null because its hidden
}
But I would like to be able to access the Base and Derived property attributes eventually like Above.
Can this be accomplished? Is there a better way?
You can use generics:
public abstract class Base<T> where T: IAttributes
{
public abstract T Attributes{ get; set; }
}
public interface IAttributes
{
string GlobalId { get; set; }
}
And
public class Derived: Base<ImplementAttributes>
{
public override ImplementAttributes Attributes { get; set; }
}
And then:
public void DoSomethingWithAttributes<T>(Base<T> b) where T : IAttributes
{
var Foo = FindFoo(b.Attributes.GlobalId);
}
You can pass Derived instances without specifying a type parameter explicitly:
Derived d = new Derived();
DoSomethingWithAttributes(d);
Let's say I have nested generic data classes similar to the following:
public class BaseRecordList<TRecord, TUserInfo>
where TRecord : BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual IList<TRecord> Records { get; set; }
public virtual int Limit { get; set; }
}
public class BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
public class BaseUserInfo
{
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
With 2 concrete versions like so:
// Project 1: Requires some extra properties
public class Project1RecordList : BaseRecordList<Project1Record, Project1UserInfo> {}
public class Project1Record : BaseRecord<Project1UserInfo>
{
public Guid Version { get; set; }
}
public class Project1UserInfo : BaseUserInfo
{
public string FavouriteFood { get; set; }
}
and
// Project 2: Some properties need alternate names for JSON serialization
public class Project2RecordList : BaseRecordList<Project2Record, Project2UserInfo>
{
[JsonProperty("allRecords")]
public override IList<Project2Record> Records { get; set; }
}
public class Project2Record : BaseRecord<Project2UserInfo> {}
public class Project2UserInfo : BaseUserInfo
{
[JsonProperty("username")]
public override string Name { get; set; }
}
I'm then happy to have 2 repositories that return Project1RecordList and Project2RecordList respectively, but at some point in my code I find myself needing to be able to handle both of these in one place. I figure that at this point I need to be able to treat both of these types as
BaseRecordList<BaseRecord<BaseUserInfo>, BaseUserInfo>
as this is the minimum required to meet the generic constraints, but trying to cast or use "as" throws up errors about not being able to convert.
Is there any way to do this, or even a more sane way to handle this situation without massive amounts of code duplication? If it makes any difference this is for a web app and there are already a large number of data classes, many of which use these nested generics.
What you are talking about is called covariance and MSDN has a great article on this here: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
First, create a new interface:
interface IBaseRecord<out TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecord inherit from the new interface:
public class BaseRecord<TUserInfo> : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
If done right, this should compile:
IBaseRecord<BaseUserInfo> project1 = new Project1Record();
IBaseRecord<BaseUserInfo> project2 = new Project2Record();
To expand this to the BaseRecordList, create IBaseRecordList:
interface IBaseRecordList<out TRecord, out TUserInfo>
where TRecord : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecordList inherit from that:
public class BaseRecordList<TRecord, TUserInfo> : IBaseRecordList<TRecord, TUserInfo>
And then use as such:
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project1 = new Project1RecordList();
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project2 = new Project2RecordList();
Once you have that setup, just add whatever properties or functions you need to use generically to the interfaces.
I created the following abstract class:
public abstract class AbstractClass
{
public abstract string Name { get; set; }
public abstract object Value { get; set; }
}
Now I want to derive two classes of the abstract class. I want to use an enum instead of the type object. My derived classes look like this:
First class:
public class InheritanceClass1:AbstractClass
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
}
Second class:
public class InheritanceClass2 : AbstractClass
{
public override string Name { get; set; }
public override SecondEnum Value { get; set; }
}
I'm getting an error showed in my code, that the type of the property Value isn't object. I tryed to use the new-keyword instead of override like this:
In my abstract class:
public object Value { get; set; }
In my derived class:
public new FirstEnum Value { get; set; }
But if I create a List<AbstractClass> I have the problem that I can't use it for example for Linq because I would retrieve the "wrong" property. It is just hided, but still there, so I have to override the property.
So how do I have to change my abstract class and my derived classes, that I can use different types in my derived classes?
You can use abstract class like this:
public abstract class AbstractClass<T>
{
public abstract string Name { get; set; }
public abstract T Value { get; set; }
}
And derived class will change like this:
public class InheritanceClass1 : AbstractClass<FirstEnum>
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
}
If you know that you will need only enums, you can add struct, IConvertible restriction to T:
public abstract class AbstractClass<T> where T : struct, IConvertible
{
public abstract string Name { get; set; }
public abstract T Value { get; set; }
}
Update based on comment:
Not the cleanest solution if you need List<AbstractClass>, but you can have additional class:
public abstract class AbstractClass
{
public abstract string Name { get; set; }
public abstract int GetValue ();
}
Which will then be inherited by AbstractClass<T>:
public abstract class AbstractClass<T> : AbstractClass where T : struct, IConvertible
{
public abstract T Value { get; set; }
}
And InheritancClass:
public class InheritanceClass1 : AbstractClass<FirstEnum>
{
public override string Name { get; set; }
public override FirstEnum Value { get; set; }
public override int GetValue () => (int)Value;
}
And then you can use it in a list:
var list = new List<AbstractClass> { new InheritanceClass1 (), new InheritanceClass2 () };
In this way you can use List<AbstractClass> with GetValue method. If you are using only enums you can always recast it to enum value. Ofcorse, you would not know exactly which enum it is, but you can add additional field for that.
I have the following two classes:
abstract class LogItem {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
class MyLogItem : LogItem
{
//No I want this to have to have the members from the abstract class above, as if it where an interface?
}
So in other words I am wanting a type if interface that can have definitions or variables which all classes that implement it have to have, but they could add more if they required ?
The above example builds, even if i dono add the members from the abstract class.
edit
Forget what I've said before. These are attributes, not methods. For them to be accessible on derived classes, you make them protected or public. The difference is that public members are visible to the world, while protected ones are visible to the class and subclasses.
Any class derived from your LogItem may have other variables.
abstract class LogItem {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
class MyLogItem : LogItem
{
//No I want this to have to have the members from the abstract class above, as if it where an interface?
private void TestMethod(){
String test = payload;
}
}
check out this post for more information
Your MyLogItem class can reference any of the above members directly. They are accessible
You may declare an interface with those
public interface MyInterface {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
and your class
public class MyLogItem : MyInterface
{
String _payload;
public String payload { get{ return _payload; } set {_payload=value;} }
...
}
The abstract keyword can also be applied to methods, as described here.