I have the following class hierarchy.
public abstract class ResourceBase { }
public abstract class WebResourceBase : ResourceBase {
public ResourceBase LocalPath { get; set; }
public ResourceBase FtpPath { get; set; }
}
public class JavaScript : WebResourceBase { }
What I would like to do is have a declaration like so.
new JavaScript() {
LocalPath = "/path/goes/here/1.js",
FtpPath = "ftp://path/goes/here/1.js"
}
The obvious answer here would be to use implicit operators but the problem is that I want to assign a derived type to those properties which is the same as the declared type so LocalPath and FtpPath would be of type JavaScript.
I'd like my solution to be more flexible than what I have at the moment. This code just makes my skin crawl. Was hoping there was a way using reflection and I have tried looking for information using the StackTrace class but no luck. Any help would be appreciated. Thanks.
public abstract class ResourceBase {
public static implicit operator ResourceBase(string path) {
if (path.EndsWith(".js"))
return new JavaScript(path);
// etc...
}
}
This assumes that WebResourceBase is actually meant to inherit ResourceBase.
You won't be able to make the implicit operator look much nicer, unfortunately - generics won't work here.
Alternative: Generics to constrain ResourceBase
Now that I've re-read it and understand what you're after, one option is to amend your classes to include a generic parameter referencing derived classes (sort of like a self-reference):
public abstract class ResourceBase
{ }
public abstract class WebResourceBase<T> : ResourceBase
where T : WebResourceBase<T>
{
public T LocalPath { get; set; }
public T FtpPath { get; set; }
}
public class JavaScript : WebResourceBase<JavaScript>
{
}
Then you will see that in JavaScript, the properties LocalPath and FtpPath are now of type JavaScript also.
Now your assignment will only accept JavaScript types:
new JavaScript()
{
LocalPath = new JavaScript("/path/goes/here/1.js"),
FtpPath = new JavaScript("ftp://path/goes/here/1.js")
}
The benefit of this approach is it will constrain the base properties to be of the current type or more derived, not less derived.
Alternative: Explicit parsing instead of implicit operator
If you need to leave the LocalPath and FtpPath variables as ResourceBase, or otherwise cannot use generics here, your implicit operator will start to get confusing. Better to provide something explicit like a static method:
new JavaScript()
{
LocalPath = JavaScript.Parse("/path/goes/here/1.js"),
FtpPath = JavaScript.Parse("ftp://path/goes/here/1.js")
}
class JavaScript
{
public static ResourceBase Parse(string s)
{
if (path.EndsWith(".js"))
return new JavaScript(path);
throw new Exception();
}
}
Alternative: Class hierarchy parsing instead of implicit operator
Bake the concept of consuming strings into the types via constructors and make the properties public read-only:
public abstract class ResourceBase
{ }
public abstract class WebResourceBase
{
public ResourceBase LocalPath { get; private set; }
public ResourceBase FtpPath { get; private set; }
protected abstract ResourceBase ParseLocalPath(string s);
protected abstract ResourceBase ParseFtpPath(string s);
}
public class JavaScript : WebResourceBase<JavaScript>
{
protected override ResourceBase ParseLocalPath(string s)
{
// etc.
}
protected override ResourceBase ParseFtpPath(string s)
{
// etc.
}
}
To be honest, most of this seems a little overkill just to get two properties set as a particular type from a string, you have loads of options - even the implicit operator will work.
Pick the one that is easiest to understand. Operator overloading tends to be somewhat hidden unless you go digging for it.
I too assume that WebResourceBase is supposed to inherit from ResourceBase
Have a protected mapping mechanism on the base class that derived classes can subscribe themselves to:
public abstract class ResourceBase
{
// Records how to make a ResourceBase from a string,
// on a per-extension basis
private static Dictionary<string, Func<string, ResourceBase>> constructorMap
= new Dictionary<string, Func<string, ResourceBase>>();
// Allows a derived type to subscribe itself
protected static void Subscribe(
string extension,
Func<string, ResourceBase> ctor)
{
if (constructorMap.ContainsKey(extension))
throw new Exception("nuh uh");
constructorMap.Add(extension, ctor);
}
// Given a string, finds out who has signed up to deal with it,
// and has them deal with it
public static implicit operator ResourceBase(string s)
{
// Find a matching extension
var matches = constructorMap.Where(kvp => s.EndsWith(kvp.Key)).ToList();
switch (matches.Count)
{
case 0:
throw new Exception(
string.Format("Don't know how to make {0} into a ResourceBase",
s));
case 1:
return matches.Single().Value(s);
default:
throw new Exception(string.Format(
"More than one possibility for making {0} into a ResourceBase",
s));
}
}
}
The intermediate type is largely unchanged, but with some type checking that I can't work out how to enforce at compile time:
public abstract class WebResourceBase : ResourceBase
{
private ResourceBase localPath;
public ResourceBase LocalPath
{
get { return localPath; }
set
{
if (value.GetType() != GetType())
{
throw new Exception("Naughty");
}
localPath = value;
}
}
private ResourceBase ftpPath;
public ResourceBase FtpPath
{
get { return ftpPath; }
set
{
if (value.GetType() != GetType())
{
throw new Exception("Naughty");
}
ftpPath = value;
}
}
}
The concrete types look like this:
public class JavaScript : WebResourceBase
{
public JavaScript()
{
}
private JavaScript(string s)
{
}
static JavaScript()
{
Subscribe("js", s => (ResourceBase)new JavaScript(s));
}
}
Usage is as you specified:
var js = new JavaScript
{
LocalPath = "hello.js",
FtpPath = "hello.js"
};
Note that despite the ResourceBase in the signature of constructorMap and Subscribe, after the above statement LocalPath and FtpPath are JavaScript objects.
I would just add an extra layer of indirection to the process (it's amazing how often that's a good answer for design questions ;) ).
I would either add a new constructor that takes two string parameters, add two additional string properties, or both. (I'll assume you're just adding two new string properties from here on; you can extrapolate from there.)
If you add a new property: JavaScriptLocalPath it can, in it's set method, convert the string into a derived type of ResourceBase specific to JavaScript and the set the LocationPath property using that result. I assume it's get method can also extract that string out of the ResourceBase (so that you don't need to bother storing the string as well).
Here's my idea:
public abstract class WebResourceBase {
public ResourceBase LocalPath { get; set; }
public ResourceBase FtpPath { get; set; }
protected abstract ResourceBase ConvertFromString(string path);
public string LocalPathStr { set { LocalPath = ConvertFromString(value); } }
public string FtpPathStr { set { FtpPath = ConvertFromString(value); } }
}
Could probably be improved.
Related
Is it possible to add different type of generic objects to a list?. As below.
public class ValuePair<T>
{
public string Name { get; set;}
public T Value { get; set;
}
and let say I have all these objects...
ValuePair<string> data1 = new ValuePair<string>();
ValuePair<double> data2 = new ValuePair<double>();
ValuePair<int> data3 = new ValuePair<int>();
I would like to hold these objects in a generic list.such as
List<ValuePair> list = new List<ValuePair>();
list.Add(data1);
list.Add(data2);
list.Add(data3);
Is it possible?
In general, you'd have to either use a List<object> or create a non-generic base class, e.g.
public abstract class ValuePair
{
public string Name { get; set;}
public abstract object RawValue { get; }
}
public class ValuePair<T> : ValuePair
{
public T Value { get; set; }
public object RawValue { get { return Value; } }
}
Then you can have a List<ValuePair>.
Now, there is one exception to this: covariant/contravariant types in C# 4. For example, you can write:
var streamSequenceList = new List<IEnumerable<Stream>>();
IEnumerable<MemoryStream> memoryStreams = null; // For simplicity
IEnumerable<NetworkStream> networkStreams = null; // For simplicity
IEnumerable<Stream> streams = null; // For simplicity
streamSequenceList.Add(memoryStreams);
streamSequenceList.Add(networkStreams);
streamSequenceList.Add(streams);
This isn't applicable in your case because:
You're using a generic class, not an interface
You couldn't change it into a generic covariant interface because you've got T going "in" and "out" of the API
You're using value types as type arguments, and those don't work with generic variable (so an IEnumerable<int> isn't an IEnumerable<object>)
Not unless you have a non-generic base-type ValuePair with ValuePair<T> : ValuePair (it would work for an interface too), or use List<object>. Actually, though, this works reasonably:
public abstract class ValuePair
{
public string Name { get; set; }
public object Value
{
get { return GetValue(); }
set { SetValue(value); }
}
protected abstract object GetValue();
protected abstract void SetValue(object value);
}
public class ValuePair<T> : ValuePair
{
protected override object GetValue() { return Value; }
protected override void SetValue(object value) { Value = (T)value; }
public new T Value { get; set; }
}
No, it is not possible. You could create, in your case, a base class ValuePair from which ValuePair<T> derives. Depends on your purposes.
it's not possible as far as I know.
the line:
List<ValuePair> list = new List<ValuePair>();
you wrote in your sample is not providing a concrete type for T and this is the issue, once you pass it, you can only add object of that specific type.
Code tells more than words, so look at this:
public abstract class ViewObject: INotifyPropertyChanged {
public virtual string Id {
get {
return this.GetType().Name;
}
}
}
public class Object : ViewObject {
private string id = string.Empty;
public override string Id {
get {
return this.id;
}
set {
this.id = value;
}
}
}
What is the correct way to implement the desired behaviour of a base implementation in the abstract class (yes, it should have a base implementation for this, but not for other things)?
I can only think of using the new keywork instead of override to simply hide the base implementation, but is this right?
you are already using inheritance. Override method is useful when method name and parameter is same.
here you can use method overloading.
for method overload name is same but parameter is different. you can use in inheritance also.
i hope this is useful
If you use the new keyword and someone casts your derived object to the base class, the base implementation will be called and not the derived one. To avoid this, the override is needed.
But that is currently not possible, cause your base class doesn't support a setter. So stick to the override and implement a set method in the base class that simply throws a NotSupportedExecption.
public abstract class ViewObject
{
public virtual string Id
{
get { return this.GetType().Name; }
set { throw new NotSupportedException(); }
}
}
public class Object : ViewObject
{
private string id = string.Empty;
public override string Id
{
get { return this.id; }
set { this.id = value; }
}
}
I am trying to create a class based on an abstract class and overwrite a function contained in the base class with another one that has a return type of "T" which is a type passed by the class.
e.g:
public abstract class DayInfo
{
public virtual void GetInfo()
{
throw new NotImplementedException();
}
}
public class DayInfo<T> : DayInfo
{
private T info;
public DayInfo(T data)
{
info = data;
}
public T GetInfo() // << This
{
return info;
}
}
Examples:
1
DayInfo info = new DayInfo<String>("Blah");
String stuff = info.GetInfo();
2
DayInfo info = new DayInfo<int>(25);
int stuff = info.GetInfo();
Is there any way to achieve this?
Edit 1:
I forgot to precise that I didn't used a class-passed type in the base class because I wanted to be able to use it as a generic type without having to define any type.
e.g:
public SortedDictionary<int, DayInfo> Data = new SortedDictionary<int, DayInfo>();
Edit 2:
Also, the point of the virtual function in the base class is that it will make the child classes throw an exception if the GetInfo() function is accessed but isn't overridden.
this is the way to achieve your goal:
public abstract class DayInfoA<T>
{
public virtual T GetInfo()
{
.......
}
}
public class DayInfoB<T> : DayInfoA<T>
{
private T info;
public DayInfoB(T data)
{
info = data;
}
public override T GetInfo() // << This
{
.........
}
}
and use it like this:
DayInfoB<int> info = new DayInfoB<int>(25);
int stuff = info.GetInfo();
Why dont you declare GetInfo() as dynamic?
This way the casting should be automatic. The only downside is that you'd lost the compiler assertions and if the variable that stores GetInfo() value can't do the cast, it'll throw a runtime error.
For example:
public abstract class DayInfo {
public abstract dynamic GetInfo();
}
public class DayInfo<T> : DayInfo {
private readonly T _info;
public DayInfo(T info) {
_info = info;
}
public override dynamic GetInfo() {
return _info;
}
}
You also could declare something like GetInfo<T>(ref T result), this way you can omit the T type from the method call and let the compiler infer it at runtime, the only downside is that you should pass the variable to store the result as an argument instead to get it returned by the method.
This can be produced with NVI pattern:
public abstract class DayInfo
{
protected virtual void GetInfoCore() {
throw new NotImplementedException();
}
// or
// protected abstract void GetInfoCore();
public void GetInfo() {
GetInfoCore();
}
}
public class DayInfo<T> : DayInfo
{
private T info;
public DayInfo(T data) {
info = data;
}
public new T GetInfo() { // << This
return info;
}
protected override void GetInfoCore() {
GetInfo();
}
}
No, not like it looks like you're wanting it (assuming you don't want to or cant alter the base class declaration). In order for the function to resolve to a polymorphic call, you need to have the same signature and return type. Otherwise it wont resolve the function polymorphically, it'll just call the base class version of the function since that's what it sees you calling (and the variable you've assigned your instance to is of the base class type).
You CAN do this, but it's pretty ugly:
DayInfo info = new DayInfo<String>("Blah");
String stuff = ((DayInfo<string>)info).GetInfo();
No, because the functions won't match up with different function signatures.
What you can do is define it like so:
public abstract class DayInfo
{
public virtual object GetInfo()
{
throw new NotImplementedException();
}
}
and in the derived class like this:
public object GetInfo() // << This
{
return info;
}
Then they would both have the same signature and the polymorphism would match up.
However, on the other end a cast will be required:
DayInfo info = new DayInfo<int>(25);
int stuff = (int)info.GetInfo();
Edit: As an aside unless there's more to it I'd make that into an interface or if the GetInfo really does nothing make the GetInfo purely abstract.
public abstract object GetInfo();
You could create a covariant interface instead of, or in addition to, a base class:
void Main()
{
IDayInfo dayInfo = new DayInfo<string>("hi!");
object info = dayInfo.GetInfo(); //info == "hi!"
}
public interface IDayInfo
{
object GetInfo();
}
public interface IDayInfo<out T> : IDayInfo
{
new T GetInfo();
}
public class DayInfo<T> : IDayInfo<T>
{
private T info;
public DayInfo(T data)
{
info = data;
}
public T GetInfo()
{
return info;
}
object IDayInfo.GetInfo()
{
return this.GetInfo();
}
}
(see Variance in Generic Interfaces for info on what covariance/contravariance are)
Note that object info (in my second line in Main) is as precise as you can get without casting in this example. Once you store the DayInfo<string> object in an IDayInfo<object> variable/field, as I did (and as you'd like to do in your dictionary), the stronger typing of string is, in a sense, forgotten and cannot be restored without a cast.
Update: added IDayInfo interface.
Is it possible to add different type of generic objects to a list?. As below.
public class ValuePair<T>
{
public string Name { get; set;}
public T Value { get; set;
}
and let say I have all these objects...
ValuePair<string> data1 = new ValuePair<string>();
ValuePair<double> data2 = new ValuePair<double>();
ValuePair<int> data3 = new ValuePair<int>();
I would like to hold these objects in a generic list.such as
List<ValuePair> list = new List<ValuePair>();
list.Add(data1);
list.Add(data2);
list.Add(data3);
Is it possible?
In general, you'd have to either use a List<object> or create a non-generic base class, e.g.
public abstract class ValuePair
{
public string Name { get; set;}
public abstract object RawValue { get; }
}
public class ValuePair<T> : ValuePair
{
public T Value { get; set; }
public object RawValue { get { return Value; } }
}
Then you can have a List<ValuePair>.
Now, there is one exception to this: covariant/contravariant types in C# 4. For example, you can write:
var streamSequenceList = new List<IEnumerable<Stream>>();
IEnumerable<MemoryStream> memoryStreams = null; // For simplicity
IEnumerable<NetworkStream> networkStreams = null; // For simplicity
IEnumerable<Stream> streams = null; // For simplicity
streamSequenceList.Add(memoryStreams);
streamSequenceList.Add(networkStreams);
streamSequenceList.Add(streams);
This isn't applicable in your case because:
You're using a generic class, not an interface
You couldn't change it into a generic covariant interface because you've got T going "in" and "out" of the API
You're using value types as type arguments, and those don't work with generic variable (so an IEnumerable<int> isn't an IEnumerable<object>)
Not unless you have a non-generic base-type ValuePair with ValuePair<T> : ValuePair (it would work for an interface too), or use List<object>. Actually, though, this works reasonably:
public abstract class ValuePair
{
public string Name { get; set; }
public object Value
{
get { return GetValue(); }
set { SetValue(value); }
}
protected abstract object GetValue();
protected abstract void SetValue(object value);
}
public class ValuePair<T> : ValuePair
{
protected override object GetValue() { return Value; }
protected override void SetValue(object value) { Value = (T)value; }
public new T Value { get; set; }
}
No, it is not possible. You could create, in your case, a base class ValuePair from which ValuePair<T> derives. Depends on your purposes.
it's not possible as far as I know.
the line:
List<ValuePair> list = new List<ValuePair>();
you wrote in your sample is not providing a concrete type for T and this is the issue, once you pass it, you can only add object of that specific type.
I have been getting a lot of traction from a builder pattern as a public class member of another class:
public class Part
{
public class Builder
{
public string Name { get; set; }
public int Type { get; set; }
public Part Build()
{
return new Part(Name, Type);
}
}
protected Part(string name, int type)
{
...
}
}
Note protected constructor - I like how I HAVE to use the builder to get a Part. Calls to
Part p = new Part.Builder() { Name = "one", Type = 1 }.Build();
work great. What I would like to do is use this builder to serve up a special kind of part based on the Type (for example):
public class SpecialPart : Part
{
protected SpecialPart(string name, int type) : base(name, type) { }
}
And a slight change to the builder:
public Part Build()
{
if (Type == _some_number_)
return new SpecialPart(Name, Type);
return new Part(Name, Type);
}
But this doesn't work - Part.Builder can't see SpecialPart's protected constructor. How can I get Builder to work with descendents of Part and get the same must-have-a-builder semantics?
There are many ways to skin a cat, but the path of least resistance here is going to be making the constructors of your various part types public or internal.
You can't do it, except for putting them in their own assembly and use the internal access specifier.