I'm trying to implement generic interface method but keep getting an error. I'm pasting the code to better explain what I want to do.
What I'm trying to achieve is: based on some input data (SomeModelA, SomeModelB) I want to get the same return type (Template).
namespace GenericInterfacePuzzle
{
class Program
{
static void Main(string[] args)
{
var workerA = new WorkerA();
var itemsBasedOnModelA = workerA.Get(new List<SomeModelA>());
var workerB = new WorkerB();
var itemsBasedOnModelB = workerB.Get(new List<SomeModelB>());
}
}
public interface IWorker
{
Template Get<T>(List<T> someModels);
}
public class WorkerA : IWorker
{
public Template Get<SomeModelA>(List<SomeModelA> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelA> models)
{
var x = models.First();
}
}
public class WorkerB : IWorker
{
public Template Get<SomeModelB>(List<SomeModelB> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelB> models)
{
var x = models.First();
}
}
public class SomeModelA
{
public string Name { get; set; }
}
public class SomeModelB
{
public string Age { get; set; }
}
public class Template
{
// Irrevelant return type
}
}
I want to know at the level of WorkerA/WorkerB class that I'm dealing with a concrete model, and based on that I want to return a Template class instance
The problem is that in the lines that call Process:
ProcessModels(someModels);
I get an error saying:
Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.List of SomeModelA' to 'System.Collections.Generic.List of GenericInterfacePuzzle.SomeModelA'
Any feedback appreciated what might be going wrong here, and why doesn't it recognize the model classes when passed to the functions.
Chris
1) You need to define the generic parameter on the level of your interface. Otherwise the T parameter is not known to the compiler:
public interface IWorker<T> where T: SomeModel
{
Template Get(List<T> someModels);
}
2) you need to make a constraint since you probably don't want any type to be given to your interface. It would be preferable to make a baseclass for your models and let them inherit from it:
public abstract class SomeModel { ... }
public class SomeModelA : SomeModel
{
public string Name { get; set; }
}
public class SomeModelB : SomeModel
{
public string Age { get; set; }
}
This way it will allow you to specify the model directly in the declaration of the class which will implement the interface (see point 3)
3) Now you need to specify in the child classes which model belongs to which workertype:
public class WorkerA : IWorker<SomeModelA>
{
public Template Get(List<SomeModelA> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelA> models)
{
var x = models.First();
}
}
public class WorkerB : IWorker<SomeModelB>
{
public Template Get(List<SomeModelB> someModels)
{
ProcessModels(someModels);
return new Template(); // let's say it's based on the result of ProcessModels
}
private void ProcessModels(List<SomeModelB> models)
{
var x = models.First();
}
}
You also should remove the generic specification in your Get method!
public Template Get<SomeModelA>(List<SomeModelA> someModels)
^
|
remove this
this is already specified when you implement the interface:
public class WorkerA : IWorker<SomeModelA>
4) and the last thing is you test in the main method:
var worker = new WorkerA();
var itemsBasedOnModelA = worker.Get(new List<SomeModelA>());
var workerB = new WorkerB();
var itemsBasedOnModelB = worker.Get(new List<SomeModelB>());
^
|
this should be [workerB]!
I have a bigger Projekt and I would like to change a variable value into the BaseClass if the variable value into the derived class are changed.
Here a simple Example.
What I want are, if I change the value Obj.ModelTyp.Name to “Name123“ then the Base.ModelTyp.Name gets the same value “Name123“ automatically.
Is there a simple way to do that?
Thanks Steffen
namespace Question
{
class Program
{
static void Main(string[] args)
{
DataObjekt Obj = new DataObjekt();
Obj.ModelTyp.Name = "Name123"; // is there a Way to Change Base.ModelTyp.Name
// if Obj.ModelTyp.Name is changed?
Obj.ModelTyp.Data = "4567";
Obj.DoSomithing();
}
}
public class FirstBaseClass
{
public FirstBaseClass() { ModelTyp = new BaseType(); }
public BaseType ModelTyp { get; set; }
}
public class SecondBaseClass : FirstBaseClass
{
public void DoSomithing()
{
string Test = this.ModelTyp.Name; // there is nothing because Base.ModelTyp.Name
//but I Want to have "Name123"
}
}
public class DataObjekt : SecondBaseClass
{
public DataObjekt() { ModelTyp = new ObjektData(); }
new public ObjektData ModelTyp { get; set; }
}
public class BaseType
{
public string Name { get; set; }
}
public class ObjektData : BaseType
{
public string Data { get; set; }
}
}
Your classes' relationships seem really complicated and convoluted. You should probably consider simplifying it a bit.
Anyway, the reason why your code does not work now is because you hid the base class' ModelTyp property, and created another new ModelTyp property in DataObjekt. Hopefully you already knew this.
But you don't really want to create a brand new, separate property, do you? You just want to change the type of ModelTyp to ObjektData. Therefore, you can just make DataObjekt.ModelTyp refer to the same thing as FirstBaseClass.ModelTyp in the constructor:
public DataObjekt() {
ModelTyp = new ObjektData();
base.ModelTyp = this.ModelTyp; // <- this line
}
I have class which have too many related calculated properties.
I have currently kept all properties are read only.
some properties need long calculation and it is called again when its related properties are needed.
How can create this complex object .Also i want these properties should not be set from external code. I need show hide as i am binding properties for UI. Also i think order is also important.
My Class is something like
public string A
{
get
{
return complexMethod();
;
}
}
public string B
{
get
{
if (A == "value")
return "A";
else return "B";
;
}
}
public bool ShowHideA
{
get
{
return string.IsNullOrEmpty(A);
;
}
}
public bool ShowHideB
{
get
{
return string.IsNullOrEmpty(B);
;
}
}
public string complexMethod()
{
string value = "";
// calculation goes here
return value;
}
}
Thanks
You need to use Lazy type provided by .net:
Lazy<YourType> lazy = new Lazy<YourType>();
Make your properties internal to not be set from external code.
Well tall order isn't it?
One of the coolest things about extension methods is you can use types. This is perfect for writing external programs to calculate property values. Start like this...
public static class XMLibrary
{
public static MC CalculateValues(this MC myclass)
{
//for each property calculate the values here
if (myclass.Name == string.Empty) myclass.Name = "You must supply a name";
if (myclass.Next == 0) myclass.Next = 1;
//when done return the type
return myclass;
}
}
public class MC
{
public string Name { get; set; }
public int Next { get; set; }
}
public class SomeMainClass
{
public SomeMainClass()
{
var mc = new MC { Name = "test", Next = 0 };
var results = mc.CalculateValues();
}
}
There are many other ways to do class validation on a model, for example dataannotations comes to mind, or IValidatableObject works too. Keeping the validation separate from the class is a good idea.
//Complex properites are simple
public class MyComplextClass{
public List<MyThings> MyThings {get;set;}
public List<FileInfo> MyFiles {get;set;}
public List<DateTime> MyDates {get;set;}
}
I don't get something, and if somebody can clarify:
I need to access this function / helper from here and there:
namespace Laf.Helpers
{
public class Common
{
public string TimeSpanToString(TimeSpan val)
{
return val.ToString(#"hh\:mm");
}
}
}
And in my controller I access it by:
var tmp = new Common();
string str = tmp.TimeSpanToString(tp.DepartureTime);
transferPoint.Add(
new ListTransferPointVM { PortName = tp.PortName, DepartureTime = str }
str);
And the question is how can I achieve and not have duplicate in every controller:
DepartureTime = TimeSpanToString(tp.DepartureTime)
Possible Answer
I just found a way that compiler is not frowning on:
public class TransferController : Controller
{
private Common common = new Common();
public ActionResult Index ()
{
...
and later, when I need it:
string time = common.TimeSpanToString((TimeSpan)variable);
You could make your method string TimeSpanToString(TimeSpan) a static method. This way you can access it without having to make a Common object. Your code will look as follows:
namespace Laf.Helpers
{
public class Common
{
public static string TimeSpanToString(TimeSpan val)
{
return val.ToString(#"hh\:mm");
}
}
}
And your Controller:
transferPoint.Add(
new ListTransferPointVM {
PortName = tp.PortName,
DepartureTime = Common.TimeSpanToString(tp.DepartureTime) }
Common.TimeSpanToString(tp.DepartureTime));
EDIT: As suggested by Michael Petrotta an extension method would be better. An implementation could be:
namespace LaF.ExtensionMethods
{
public static class MyExtensions
{
public static string TimeSpanToString(this TimeSpan ts)
{
return ts.ToString(#"hh\:mm");
}
}
}
You can now call the method like:
tp.DepartureTime.TimeSpanToString();
More on Extension Methods in C#
Suppose I have a base class named Visitor, and it has 2 subclass Subscriber and NonSubscriber.
At first a visitor is start off from a NonSubscriber, i.e.
NonSubscriber mary = new NonSubscriber();
Then later on this "mary" subscribed to some services, and I want to change the type of "mary" to Subscriber.
What is the conventional way to do that?
can't do that. sorry. C# is not a dynamic language.
You will have to create a new mary = new Subscriber(); and copy all relevant properties.
But a better approach might be to model it differently: Give Visitor a list of subscriptions. An empty list means a NonSubscriber.
You cant do this type of conversion.
What you should do is treat mary as a visitor, and when time arrives, create a new instance of "subscriber":
Visitor mary = new NonSubscriber();
// Do some Visitor operations
...
// Now mary is a Subscriber
mary = new Subscriber();
You could use the GOF design patterns State or Strategy to model such an behaviour. Using these patterns, it seems during runtime as if the class of the objects has been changed.
It seems that you have some design problems. I think that it would be better to redesign your code like:
class Visitor
{
private bool isSubscriber = false;
public bool IsSubscriber
{
get { return isSubscriber; }
}
public void Subscribe()
{
// do some subscribing stuff
isSubscriber = true;
}
public void Unsubscribe()
{
// do some unsubscribing stuff
isSubscriber = false;
}
}
You cannot change the type of a variable at runtime. You need to create a new instance.
mary = new Subscriber();
Create a Subscriber constructor that takes a NonSubscriber object as a parameter, or create a method on the NonSubscriber object that returns a Subscriber to save you having to writer the mappping code in multiple places.
It seems like you are encoding information incorrectly into your class hierarchy. It would make more sense to use a different pattern than sub classing here. For example, use only one class (visitor, or perhaps you could name it potential subscriber, whatever seems appropriate) and encode information on the services the object is subscribed to, moving the dynamically changing behavior behind a "Strategy" pattern or some such. There's very little detail in your example, but one thing you could do in C# is to make a "subscriber" property which would change the behavior of the object when the state of the property was changed.
Here's a contrived somewhat related example:
class Price
{
private int priceInCents;
private bool displayCents;
private Func<string> displayFunction;
public Price(int dollars, int cents)
{
priceInCents = dollars*100 + cents;
DisplayCents = true;
}
public bool DisplayCents
{
get { return displayCents; }
set
{
displayCents = value;
if (displayCents)
{
this.displayFunction = () => String.Format("{0}.{1}", priceInCents / 100, priceInCents % 100);
}
else
{
this.displayFunction = () => (priceInCents / 100).ToString();
}
}
}
public string ToString()
{
return this.displayFunction();
}
}
public class User
{
public Subscription Subscription { get; set; }
public void HandleSubscription()
{
Subscription.Method();
}
}
public abstract class SubscriptionType
{
public abstract void Method();
}
public class NoSubscription : SubscriptionType
{
public override void Method()
{
// Do stuff for non subscribers
}
}
public class ServiceSubscription : SubscriptionType
{
public override void Method()
{
// Do stuff for service subscribers
}
}
public class Service2Subscription : SubscriptionType
{
public override void Method()
{
// Do stuff for service2 subscribers
}
}
Think the code explains my answer :)
Adding to the other answers and your comment, you indeed can use the state pattern for your purpose, it would go something like this:
public class MyProgram
{
public void Run()
{
Visitor v = new Visitor("Mary");
Debug.Assert(v.SubscriptionLinkText == "Join now");
v.IsSubscribed = true;
Debug.Assert(v.SubscriptionLinkText == "Today's special");
v.IsSubscribed = false;
Debug.Assert(v.SubscriptionLinkText == "Join now");
}
}
public class Visitor
{
public string Name { get; set; }
private bool _isSubscribed;
public bool IsSubscribed
{
get { return this._isSubscribed; }
set
{
if (value != this._isSubscribed)
{
this._isSubscribed = value;
this.OnSubscriptionChanged();
}
}
}
private SubscriptionBase _subscription;
public string SubscriptionLinkText
{
get { return this._subscription.LinkText; }
}
public Visitor(string name)
{
this.Name = name;
this._isSubscribed = false;
this.OnSubscriptionChanged();
}
private void OnSubscriptionChanged()
{
// Consider also defining an event and raising it here
this._subscription =
SubscriptionBase.GetSubscription(this.IsSubscribed);
}
}
abstract public class SubscriptionBase
{
// Factory method to get instance
static public SubscriptionBase GetSubscription(bool isSubscribed)
{
return isSubscribed ?
new Subscription() as SubscriptionBase
: new NoSubscription() as SubscriptionBase;
}
abstract public string LinkText { get; }
}
public class Subscription : SubscriptionBase
{
public override string LinkText
{
get { return "Today's Special"; }
}
}
public class NoSubscription : SubscriptionBase
{
public override string LinkText
{
get { return "Join now"; }
}
}