This was from my university C# - windows forms exam, im trying to resolve some old subjects, but i seem to find myself stuck in this situation. This is my code:
abstract class CarFile
{
private string marca;
private readonly string serie;
public CarFile(string marca, string serie)
{
this.marca = marca;
this.serie = serie;
}
public string GetMarca
{
get { return this.marca; }
set { this.marca = value; }
}
public string GetSerie
{
get { return this.serie; }
}
public abstract string GetDescriere();
}
Then I have to do this:
my second class called ServiceFile : CarFile, ICloneable. in this class i have an array or list of strings called RepairComands which contains the necessary repairs.
- a private atribute called "motor" which can only take the following vallues {gas,gpl,hibrid} .
- a constructor which throws a generic exception if "serie==null"
-overrides the abrstract method getDescriere() to return the complete description of the car file
this is my code:
public class MyException : System.Exception
{
public MyException(string mesaj) : base(mesaj) { }
}
class ServiceFile : CarFile, ICloneable, IComparable, IReparabil
{
string[] RepairComands;
private enum motor { motorina, benzina, GPL, electric, hibrid };
public ServiceFile(string serie, string marca, string[] RepairComands):base(serie,marca){
if (serie == null)
{
throw new MyException("MESAJ");
}
this.RepairComands = RepairComands;
}
//not sure if this is correct
public override string GetDescriere()
{
string msj = string.Format("the car {0} with serial {1} and necess. repairs {2}", this.GetMarca, this.GetSerie, this.RepairComands);
return msj;
}
public object Clone()
{
ServiceFile clone = new ServiceFile(this.GetSerie, this.GetMarca, this.RepairComands);
return clone;
}
//implemented IComparable to be able to compare here 2 files by the number of repairs needed
public int CompareTo(object obj)
{
ServiceFile altafisa = (ServiceFile)obj;
if (this.RepairComands != altafisa.RepairComands)
return 1;
else return 0;
}
//overloads ToString to return the complete file description
public override string ToString()
{
return this.GetMarca + " "+ this.GetSerie + " " + this.RepairComands;
}
}
}
so far so good. this actually works.
but my problem comes now:
I have to define the interface IRep which contains 2 methods : void RepairCar() and void AddRepair(string repair).
THen ServiceFile class implements : IRep, and the function RepairCar() will be used for removing the last repair from the collection RepairComands
and the function AddRepair(string repair) will be used to add a repair in the collection RepairComands.
(For allowing the access to the private list of Repairs we should overload the index operator[] )
Thank you so much for your help, I'm a beginnes in C# and just wanted to understand better this subject that was given in my class so i could learn
Thank you
Related
I have different types of item. Each of them has a enum where ID's are keept. I want my base class to have a method to check if the item's ID is on a given list. Something like:
abstract class Thing
{
public string Name;
public int Amount;
//others
abstract bool IsInList(list<xxxxx> list);
abstract xxxxxxx ID;
}
class Fruit : Thing
{
public IDs = {F_NotSet, F_Banana, F_Apple, ...}
public IDs ID = IDs.F_NotSet;
public bool IsInList(List<T> list) //this wont compile
{
if(typeof(T) == typeof(IDs))
return list.Contains(IDs);
else
return false;
}
}
The thing is that I also have a (blazor) UI component that visualizes things so I want to be able to do my
<div>#Thing.Name [#Thing.Amount]</div>
<code>
[Parameter] public Thing Thing {get;set;}
</code>
And use it on my page for all kind of things, like :
<div>
#foreach(var thing in Things) //things being List<Thing>
{
<ThingViewer ItemToShow=thing/>
}
</div>
That's why I don't want to go the Thin<T>path because then my UI component to visualize Things and my page gets messy.
On the other side, I would like to use this "IsInList" method from the page to do things like
<div>
#foreach(var thing in MyThings) //MyThings being List<Thing>
{
#if(thing.IsInList(ThingsInOffer))
{
<div class="offer">
<ThingsVisualizer ItemToShow=thing/>
</div>
}
}
</div>
Here is the complete working example from fiddle, that helped solve the issue:
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Collections.Generic;
public class Program
{
// Just for showcasing:
public static void Main()
{
var apple = new Fruit(Fruits.Apple);
var banana = new Fruit(Fruits.Banana);
var orange = new Fruit(Fruits.Orange);
var strawberry = new Nut(Nuts.Strawberry);
var assortedFruits = new []{ Fruits.Apple, Fruits.Orange };
Console.WriteLine("I ({0}) am {1}an assorted fruit!", apple.Id, apple.IsInList(assortedFruits)?"":"not ");
Console.WriteLine("I ({0}) am {1}an assorted fruit!", banana.Id, banana.IsInList(assortedFruits)?"":"not ");
Console.WriteLine("I ({0}) am {1}an assorted fruit!", strawberry.Id, strawberry.IsInList(assortedFruits)?"":"not ");
PrintDetails(apple);
PrintDetails(banana);
PrintDetails(orange);
PrintDetails(strawberry);
foreach( var thing in new IThing[]{apple, strawberry} )
{
Console.WriteLine($"{thing.Name}s have {thing.SomeProperty}");
}
}
public static void PrintDetails(IThing thing)
{
// Going by an interface: We do not really care, what kind of
// "thing" it is in particular.
thing.Print();
}
}
// Two "Kinds" of Things: Fruits and Nuts
public enum Fruits
{
Apple,
Banana,
Orange
}
public enum Nuts
{
Strawberry
}
// Things all kinds of "Things" need to be able to do:
public interface IThing
{
void Print();
string Name {get;}
string SomeProperty {get;}
}
// Common generic implementations:
public abstract class Thing<TIdentifyingThing> : IThing
{
protected TIdentifyingThing _me;
protected Thing(TIdentifyingThing id)
{
_me = id;
}
public TIdentifyingThing Id => _me;
public string Name => _me.ToString();
public abstract string SomeProperty {get;}
// I think the "thing" here was that you can have generic methods
// with Types that do not need to be the same as the generic class's
// type. Here `T` versus `TIdentifyingThing`.
public bool IsInList<T> (IEnumerable<T> list)
{
if( typeof(T) != typeof(TIdentifyingThing) ) return false;
if( list is not null && list.Any() )
{
return list.Cast<TIdentifyingThing>().Contains(_me);
}
return false;
}
public abstract void Print();
}
// The specific Things:
public class Fruit : Thing<Fruits>
{
public Fruit( Fruits identity ): base(identity) {}
public override string SomeProperty => "just some property.";
public override void Print()
{
Console.WriteLine($"My fruity details are: I am a{(Id.ToString().StartsWithVocal() ? "n" : "" )} {Id}.");
}
}
public class Nut : Thing<Nuts>
{
public Nut( Nuts identity ): base(identity) {}
public override string SomeProperty => "not always the appearance you expect.";
public override void Print()
{
Console.WriteLine($"My nutty details are: I am a{(Id.ToString().StartsWithVocal() ? "n" : "" )} {Id}.");
}
}
// Just so the code is complete. Doesn't actually contribute to the solution as such.
public static class StringExtensions
{
public static bool StartsWithVocal(this string me)
{
return Regex.IsMatch(me, "^[aeiouAEIOU]");
}
}
Based on https://gigi.nullneuron.net/gigilabs/data-driven-tests-with-nunit/ website. I have try to create a simple testcase which prepare for read data in the future. But I have no idea how to handle Argument and use it properly
I have try to set as a object, but i think this might not be a correct solution
[TestCaseSource("GetDataString")]
public void TestMethod2(object configs)
{
}
Here is source code
namespace SAP
{
[TestFixture]
public class Scenario1
{
// This one Give System.ArgumentException
[TestCaseSource("GetDataString")]
public void TestMethod(List<Config> configs)
{
Console.WriteLine("Config " + configs);
}
// This one can handle an Exception
[TestCaseSource("GetDataString")]
public void TestMethod2(object configs)
{
}
public static List<Config> GetDataString()
{
var datas = new List<Config>();
datas.Add(new Config("Nick", "Coldson"));
return datas;
}
}
public class Config
{
public string NickName { get; set; }
public string Name { get; set; }
public Config(string nickname, string name)
{
NickName = nickname;
Name = name;
}
}
}
Here is error msg
System.ArgumentException : Object of type 'SAP.Config' cannot be
converted to type 'System.Collections.Generic.List`1[SAP.Config]'.
The testcasesource has slightly different definition pattern. Assuming you use nunit 3 it should be:
[TestCaseSource(typeof(MyTestData), nameof(GetDataString))]
public void TestMethod2(List<Config> configs)
{
...
}
public class MyTestData
{
public static IEnumerable GetDataString()
{
var datas = new List<Config>();
datas.Add(new Config("Nick", "Coldson"));
return new TestCaseData(datas);
}
}
For more info, check the documentation:
https://github.com/nunit/docs/wiki/TestCaseData
Your GetDataString returns a List<Config>.
Meaning, your test method with a [TestCaseSource("GetDataString")] will be executed as many times as many items the list has and your method must match the item type.
//// This one throws System.ArgumentException
//[TestCaseSource("GetDataString")]
//public void TestMethod(List<Config> configs)
//{
// Console.WriteLine("Config " + configs);
//}
// This one is ok
[TestCaseSource("GetDataString")]
public void TestMethod(Config config)
{
Console.WriteLine(config);
}
If you need to get List<Config> instances in your test, then your source must return some collection containing list items.
My brain is gonna to explode. :) So I would like to get help from you.
Please, think about my question like about just programmer puzzle. (Actually. perhaps it is very easy question for you, but not for me.)
It is needed to create array of objects. For example List where T is class. (I will describe Class T below). Also it is needed create “container” that will contain this array and some methods for work with this array. For example Add(), Remove(int IndexToRemove).
Class T must have field "Container", this way each elements of our array would be able to know where is it contained and has access its container's fields and methods. Notice, that in this case Class T should have type parameter. Indeed, it is not known beforehand which container's type is used.
Let us denote this class container as A and class element (class T) as AUnit.
Code:
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Add();
a.Units[0].SomeField +=100;
Console.ReadKey();
}
}
class A
{
public List<AUnit> Units;
public A()//ctor
{
Units = new List<AUnit>();
}
public void Add()
{
this.Units.Add(new AUnit(this));
}
}
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
}
Public fields should be protected or private of course, but let think about this later.
You can ask “why we create public A Container field in AUnit”? We create field public string Name{get;private set;} (actually property but nevermind). And also we would like to be able to change value of this field for example method [Class AUnit] public bool Rename(string newName)();. The main idea of this method is changing Name field only that case if no one element in array (public List Units; ) has the same name like newName. But to achieve this, Rename method has to have access to all names that is currently used. And that is why we need Container field.
Code of extended version AUnit
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (AUnit unt in this.Container.Units)
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
Ok. If you still read it let's continue. Now we need to create Class B and class BUnit which will be very similar like Class A and Class Aunit. And finally the main question of this puzzle is HOW WE CAN DO IT? Of course, I can CopyPaste and bit modify A and AUnit and create this code.
class B
{
public List<BUnit> Units; //Only Type Changing
public B()//ctor Name changing...
{
Units = new List<BUnit>();//Only Type Changing
}
public void Add()
{
this.Units.Add(new BUnit(this));//Only Type Changing
}
}
class BUnit
{
public int SomeField;
public B Container;//Only Type Changing
public string Name { get; private set; }
public A a; //NEW FIELD IS ADDED (just one)
public BUnit(B container) //Ctor Name and arguments type changing
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
this.a=new A(); //New ROW (just one)
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (BUnit unt in this.Container.Units) //Only Type Changing
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
And I can to use this classes this way.
static void Main(string[] args)
{
B b = new B();
b.Add();
b.Units[0].a.Add();
b.Units[0].a.Units[0].SomeField += 100;
bool res= b.Units[0].a.Units[0].Rename("1");
res = b.Units[0].a.Units[0].Rename("1");
Console.ReadKey();
}
This construction is can be used to create “non-homogeneous trees”.
Help, I need somebody help, just no anybody…. [The Beatles]
I created B and BUnit using CopyPaste.
But how it can be done using “macro-definitions” or “Generic”, inherit or anything else in elegant style? (C# language)
I think that there is no reason to describe all my unsuccessful attempts and subquestions. Already topic is too long. : )
Thanks a lot if you still read it and understand what I would like to ask.
You need to implement a base type, lets call it UnitBase, with all common functionality. I'd structure your code the following way:
Create an interface for your container, this way you can change implementation to more performant solutions without modifying the elements you will be adding to the container.
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
}
Following the idea stated in 1, why not make the search logic belong to the container? It makes much more sense, as it will mostly depend on how the container is implemented:
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
bool Contains(string name);
}
A specific implementation of IContainer could be the following:
public class Container : IContainer
{
public Container()
{
list = new List<UnitBase>();
}
private List<UnitBase> list;
public Q Add<Q>() where Q: UnitBase, new()
{
var newItem = Activator.CreateInstance<Q>();
newItem.SetContainer(this);
list.Add(newItem);
return newItem;
}
public IEnumerable<UnitBase> Units => list.Select(i => i);
public bool Contains(string name) =>
Units.Any(unit => unit.Name == name);
}
Create a base class for your AUnit and BUnit types condensing all common functionality:
public abstract class UnitBase
{
protected UnitBase()
{
}
public IContainer Container { get; private set; }
public int SomeField;
public string Name { get; private set; }
public void SetContainer(IContainer container)
{
Container = container;
}
public bool Rename(String newName)
{
if (Container.Contains(newName))
return false;
this.Name = newName; //No need to use String.Copy
return true;
}
}
Implement your concrete types:
public class BUnit : UnitBase
{
public int SpecificBProperty { get; private set; }
public BUnit()
{
}
}
Shortcomings of this approach? Well, the container must be of type <UnitBase>, I've removed the generic type because it really wasn't doing much in this particular case as it would be invariant in the generic type.
Also, keep in mind that nothing in the type system avoids the following:
myContainer.Add<BUnit>();
myContainer.Add<AUnit>();
If having two different types in the same container is not an option then this whole set up kind of crumbles down. This issue was present in the previous solution too so its not something new, I simply forgot to point it out.
InBetween , I am very thankful to you for your advices. Actually I can't say that I understood your answer in full, but using your ideas I have done what I want.
Looks like my variant works well. However I would like to hear your (and everyone) opinions about code described below. The main goal of this structure is creating non-homogeneous trees. So could you estimate it from this side.
First of all. We need to create interfaces for both classes. We describe there all "cross-used" functions.
public interface IUnit<T>
{
string Name { get;}
void SetContainer(T t);
bool Rename(String newName);
}
public interface IContainer
{
bool IsNameBusy(String newName);
int Count { get; }
}
Next. Create Base for Unit Classes for future inheritance. We will use in this inheritors methods from Container Base so we need generic properties and IUnit interface.
class UnitBase<T> : IUnit<T> where T : IContainer
Unfortunately I don't know yet how to solve the problem with Constructor parameters. That is why I use method
SetContainer(T container).
Code:UnitBase
class UnitBase<T> : IUnit<T> where T : IContainer
{
protected T Container;
public string Name { get; private set; }
public UnitBase()
{
this.Name = "Default";
}
public void SetContainer(T container)
{
this.Container = container;
}
public bool Rename(String newName)
{
bool res = Container.IsNameBusy(newName);
if (!res) this.Name = String.Copy(newName);
return !res;
}
}
Next. Create ContainerBase
ContainerBase should:
1) has IContainer interface.
2)has information about what it will contain:
... where U : IUnit<C>, new()
3)and .... has information about what itself is. This information we need to pass as parameter to SetContainer() method.
Code ContainerBase:
class ContainerBase<U, C> : IContainer //U - Unit Class. C-Container Class
where U : IUnit<C>, new()
where C : ContainerBase<U, C>
{
protected List<U> Units;
public U this[int index] { get { return Units[index]; } }
public ContainerBase()//ctor
{
this.Units = new List<U>();
}
public void Add()
{
this.Units.Add(new U());
this.Units.Last().SetContainer(((C)this));//may be a bit strange but actualy this will have the same type as <C>
}
public bool IsNameBusy(String newName)
{
bool res = false;
foreach (var unt in this.Units)
{
if (unt.Name == newName)
{
res = true;
break;
}
}
return res;
}
public int Count { get { return this.Units.Count; } }
}
Cast ((TContainer)(this)) may be is a bit strange. But using ContainerBase we always should use NewInheritorContainer. So this cast is just do nothing…looks like...
Finally. This classes can be used like in this example.
class SheetContainer : ContainerBase<SheetUnit,SheetContainer> {public SheetContainer(){}}
class SheetUnit : UnitBase<SheetContainer>
{
public CellContainer Cells;
public PictureContainer Pictures;
public SheetUnit()
{
this.Cells = new CellContainer();
this.Pictures = new PictureContainer();
}
}
class CellContainer : ContainerBase<CellUnit, CellContainer> { public CellContainer() { } }
class CellUnit : UnitBase<CellContainer>
{
public string ValuePr;//Private Field
private const string ValuePrDefault = "Default";
public string Value//Property for Value
{
//All below are Just For Example.
get
{
return this.ValuePr;
}
set
{
if (String.IsNullOrEmpty(value))
{
this.ValuePr = ValuePrDefault;
}
else
{
this.ValuePr = String.Copy(value);
}
}
}
public CellUnit()
{
this.ValuePr = ValuePrDefault;
}
}
class PictureContainer : ContainerBase<PictureUnit, PictureContainer> { public PictureContainer() { } }
class PictureUnit : UnitBase<PictureContainer>
{
public int[,] Pixels{get;private set;}
public PictureUnit()
{
this.Pixels=new int[,]{{10,20,30},{11,12,13}};
}
public int GetSizeX()
{
return this.Pixels.GetLength(1);
}
public int GetSizeY()
{
return this.Pixels.GetLength(0);
}
public bool LoadFromFile(string path)
{
return false;
}
}
static void Main(string[] args)
{
SheetContainer Sheets = new SheetContainer();
Sheets.Add();
Sheets.Add();
Sheets.Add();
Sheets[0].Pictures.Add();
Sheets[1].Cells.Add();
Sheets[2].Pictures.Add();
Sheets[2].Cells.Add();
Sheets[2].Cells[0].Value = "FirstTest";
bool res= Sheets[0].Rename("First");//res=true
res=Sheets[2].Rename("First");//res =false
int res2 = Sheets.Count;
res2 = Sheets[2].Pictures[0].Pixels[1, 2];//13
res2 = Sheets[2].Pictures.Count;//1
res2 = Sheets[1].Pictures.Count;//0
res2 = Sheets[0].Pictures[0].GetSizeX();//3
Console.ReadKey();
}
Looks like it works like I want. But I didn’t test it full.
Let me say Thank you again, InBetween.
The design problem is as follows, actual problem consists of 2 modules.
Module 1 classes (External Assembly)
abstract class Letter
{
private int _id;
protected Letter(int id) { _id = id; }
public abstract string Val { get; }
}
class LetterA : Letter
{
public LetterA(int id) : base(id) {}
public override string Val
{
get { return "A"; }
}
}
class WordWithALettersOnly
{
public IList<LetterA> ALetters { get; set; }
}
Module 2 classes
class LetterSmallA : LetterA
{
public LetterSmallA(int id) : base(id) {}
public override string Val
{
get { return "a"; }
}
}
class WordWithSmallALettersOnly : WordWithALettersOnly
{
private IList<LetterSmallA> _aLetters;
public new IList<LetterSmallA> ALetters
{
get { return _aLetters; }
set
{
_aLetters = value;
if(_aLetters != null)
base.ALetters = value.Cast<LetterA>().ToList(); // <-- reference lost
}
}
}
class Program
{
static void Main(string[] args)
{
var smallAWordOnly = new WordwithSmallALettersOnly();
smallAWordOnly.ALetters = new List<LetterSmallA>(){new LetterSmallA(1)};
Console.WriteLine("d : " + smallAWordOnly.ALetters.Count); // --> 1
Console.WriteLine("b : " + ((WordwithALettersOnly)smallAWordOnly).ALetters.Count); // --> 1
smallAWordOnly.ALetters.Add(new LetterSmallA(2)); --> 2
Console.WriteLine("d : " + smallAWordOnly.ALetters.Count);
Console.WriteLine("b : " + ((WordwithALettersOnly)smallAWordOnly).ALetters.Count); // -> 1
}
}
Essentially derived classes are generated in the module 2 and processed in the external assembly module 1, on a/c reference loss.
Is the only way to translate the derived class objects of the module 2 to module 1 class objects
I hope i have been explain clearly the issue, if not i do apologise, would really appreciate solutions to this.
If I understand your question correctly, what you want is to treat IList<LetterSmallA> as IList<LetterA>. This is not possible in C# and for very good reasons: one of the things IList<LetterA> says is possible to do with is is to “try to add any LetterA to it. This is not possible with IList<LetterSmallA> and so there is no built-in way to do what you want.
What you can do is to create your own implementation of IList<T> that wraps another IList<T> of derived type:
class BaseTypeList<TBase, TDerived> : IList<TBase>
where TBase : class
where TDerived : class, TBase
{
private readonly IList<TDerived> m_derivedList;
public BaseTypeList(IList<TDerived> derivedList)
{
m_derivedList = derivedList;
}
public IEnumerator<TBase> GetEnumerator()
{
return m_derivedList.Cast<TBase>().GetEnumerator();
}
public void Add(TBase item)
{
var derivedItem = item as TDerived;
if (derivedItem == null)
throw new ArgumentException();
m_derivedList.Add(derivedItem);
}
public void Clear()
{
m_derivedList.Clear();
}
// other members implemented in a similar fashion
}
(The class constraints are not necessary, but make some code simpler.)
Your setter for ALetters could then look like this:
_aLetters = value;
if(_aLetters == null)
base.ALetters = null;
else
base.ALetters = new BaseTypeList<LetterA, LetterSmallA>(value);
I got an abstract base class
public class Base
{
public abstract String Info { get; }
}
and some children.
public class A : Base
{
public override String Info { get { return "A does ..."; } }
}
public class B : Base
{
public override String Info { get { return "B does ..."; } }
}
This is mere a constant but I want to make sure using Base that all classes implement it.
Now I sometimes do not have an object instance but want to access A.Info - this is not possible due it is a instance property.
Is there another way than implementing the same property on instance AND on static level? That would be feel like a duplicate violating DRY programming style.
NEW EDIT: I now see this two solutions:
public class Base
{
public abstract String ClassInfo { get; }
}
public class A : Base
{
public override String ClassInfo { get { return Info; } }
public static String Info { get { return "A does ..."; } }
}
public class B : Base
{
public override String ClassInfo { get { return Info; } }
public static String Info { get { return "In B we do ..."; } }
}
With this I can do with any object of type Base something like object.ClassInfo but also use the value in my factory hardcoded like if(A.Info) return new A(). But I have to implement two properties for the same information in every class.
On the other hand:
public class Base
{
public abstract String ClassInfo { get; }
public static String GetClassInfo<T>() where T : BaseControl, new()
{
T obj = new T();
return obj.ClassInfo;
}
}
public class A : Base
{
public override String ClassInfo { get { return "text A"; } }
}
public class B : Base
{
public override String ClassInfo { get { return "text B"; } }
}
Due to the abstract Base it is made sure that ClassInfo is always implemented. Calls with obj.ClassInfo and Base.GetClassInfo<A>() are okay. But with this every child of Base must have a default constructor without arguments and we loose performance with the unneccessary created instance.
Is there any other idea? Which one would you prefer and why?
If you need specific return results of your static properties, you're better of either
a) Instance properties
2) Attributes
In the example you've already given, you've got an instance of Base, which means you can just make the instance property virtual:
public class Base
{
public virtual string Info { get { return "From Base"; } }
}
public class A : Base
{
public override string Info { get { return "From A"; } }
}
If you wanted to go the attribute route, you define it as such:
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public class InfoAttribute : Attribute
{
public InfoAttribute(string info) { this.Info = info; }
public string Info { get; private set; }
}
[InfoAttribute(Info = "From Base")]
public class Base
{
public string GetInfo()
{
var attr = GetType()
.GetCustomAttributes(typeof(InfoAttribute), true)
.FirstOrDefault();
return (attr == null) ? null : attr.Info;
}
}
[InfoAttribute(Info = "From A")]
public class A : Base { }
If you wanted to call it as a static function call, you could make this change:
public static string GetInfo(Base instance)
{
var attr = instance.GetType()
.GetCustomAttributes(typeof(InfoAttribute), true)
.FirstOrDefault();
return (attr == null) ? null : attr.Info;
}
And then call it as: Base.GetInfo(instance);. All in all, not very elegant!
This is not possible.
static members cannot be virtual or abstract.
You should make an abstract instance property.
Statics can't be overridden. If you truly want to do something like that, you'd want an instance property that is virtual in the base that gets overridden in the subclasses.
Does it compiled? I don't think so. Static cannot be marked as override, virtual or abstract.