Is it possible to selectively chose (with a decorator maybe?) what methods are exposed to an object based on a constructor that is called?
For example my class has 2 constructors, an empty one and one that passes in a file path string.
public class MyClass
{
private readonly string _filePath;
public MyClass()
{
}
public MyClass(string filePath)
{
_filePath = filePath
}
public Export()
{
var fi = new FileInfo(_filePath);
}
}
Is it possible that when I create a new MyClass object that only if I use the constructor with the parameter to expose the Export method?
var myClass = new MyClass();
//myClass.Export() not available
var myClass = new MyClass(#"C:\");
//myClass.Export() is available
This is a sign that you should have two different types. Perhaps they both should be sub-types of a parent type (possibly abstract) or perhaps one should simply extend the other.
Then you can construct an instance of the appropriate type based on whether or not you have a string. The type with a string can have an additional method.
public class MyClass
{
public MyClass()
{
}
public void Foo()
{
//todo do stuff
}
}
public class BetterMyClass : MyClass
{
private readonly string _filePath;
public BetterMyClass(string filePath)
{
_filePath = filePath;
}
public void Export()
{
var fi = new FileInfo(_filePath);
}
}
And then your usage works just fine:
var myClass = new MyClass();
//myClass.Export(); //syntax error
var myClass2 = new BetterMyClass(#"C:\");
myClass.Export(); //works
Not directly. You could:
Create a factory method that returns an object of type IMyInterface, and then attempt to cast to the type containing the method you wish to expose. The cast will fail if the object is not the type exposing the method. Or..
Using a dynamic object. The method call will fail at runtime if the method does not exist.
This is possible, just not in the way you are showing here. You would want to create a new class that has only a default constructor and no Export method. Then create a second class that inherits from the first and have a constructor that requires the string and also exposes the Export method.
public class MyClass
{
public MyClass()
{ }
}
public class MyOtherClass : MyClass
{
private readonly string value;
public MyOtherClass(string value)
{
this.value = value;
}
public string Export() { return this.value; }
}
If you absolutely must have the selectivity, which is a silly design decision in my opinion, then you would want to go with a type that is built at runtime using code generation that either does or does not implement the method.
To my knowledge, no, this cannot be done in the way you mean. If you could, the compiler would generally have no way to know if the method in question was valid for the object in question. It would then have to check at run-time. If you called the method when not available, you would receive a runtime exception. You can throw an exception yourself based on a flag set in the constructor.
Ultimately, however, it's likely that what you really want is a subclass which has additional options. That would be a safer way to enable this type of functionality.
You could do this using the factory pattern and returning a different interface
public interface IExportInterface
{
void Export();
}
public interface INoExportInterface
{
//Other methods
}
internal class MyClass : IExportInterface, INoExportInterface
{
private readonly string _filePath;
public MyClass()
{
}
public MyClass(string filePath)
{
_filePath = filePath;
}
public void Export()
{
var fi = new FileInfo(_filePath);
}
}
public class MyClassFactory
{
public static IExportInterface GetMyClass(string filePath)
{
return new MyClass(filePath);
}
public static INoExportInterface GetMyClass()
{
return new MyClass();
}
}
Related
I want to get the Lazy instance in another class the problem is that the T type is only set in the main class
the first class where the instance is is this:
public class singleton<T> where T : class, new()
{
private readonly static Lazy<T> val = new Lazy<T>(() => new T());
public static T instance { get { return val.Value; } }
public int UserID {get;set;}
}
now I have a other class for all user datas
public class User
{
public string Name()
{
return data.GetUserFromID(singleton.instance.UserID)
}
}
the singleton is not working because I need the Argument but the T is only in the main class
public class main : singleton<main>
{
public main()
{
UserID = 5;
}
}
EDIT
how do I get the ID from the singleton class inside another class like this
singleton file
public class singleton<T> where T : class, new()
{
private readonly static Lazy<T> val = new Lazy<T>(() => new T());
public static T instance { get { return val.Value; } }
public int UserID {get;set;}
private singleton() {
Datas.UserID = UserID;
}
}
another file
public class Datas {
public static int UserID {get;set;}
}
the singleton is not working because I need the Argument but the T is only in the main class
All you need do is change your code from:
public class User {
public string Name() {
return data.GetUserFromID(singleton.instance.UserID)
}
}
...to specifying the generic type argument:
public class User
{
public string Name()
{
var m = singleton<main>.instance;
Console.WriteLine($"Inside User.Name, m.UserId = {m.UserID}");
return "todo";
}
}
This is required because your client code is accessing the generic base directly. Had you encapsulated it into a factory manager or similar, clients would not need to specify the type.
Here is a little test harness
private void Run()
{
var x = singleton<main>.instance;
Console.WriteLine($"x.UserId = {x.UserID}");
var y = singleton<main>.instance;
Console.WriteLine($"y.UserId = {y.UserID}");
x.UserID++;
Console.WriteLine($"x.UserId = {x.UserID}");
Console.WriteLine($"y.UserId = {y.UserID}");
var user = new User();
Console.WriteLine($"User.Name = {user.Name()}");
var mp = MissPiggy.Instance;
}
Which produces the following results. Note how changing properies on two different variables modifies the same singleton.
There are a few problems too with how you are implementing singletons. A singleton class should have a private constructor and it should be the one managing lifetimes and not a secondary class.
e.g.
public sealed class MissPiggy
{
private static Lazy<MissPiggy> _instance = new Lazy<MissPiggy>(() => new MissPiggy());
private MissPiggy()
{
}
public static MissPiggy Instance
{
get { return _instance.Value; }
}
}
singleton<t> is a generic type - you can't refer to it without a generic type parameter.
Under the hood, it's actually generating new types.
So when you do this:
var mainSingleton = singleton<main>.instance;
It's actually creating a new type which looks like this:
public class NewGenericTypeWithWeirdName
{
private readonly static Lazy<main> val = new Lazy<main>(() => new main());
public static main instance { get { return val.Value; } }
public int UserID { get; set; }
}
...and if you declare var otherSingleton = singleton<SomethingElse>.instance; then it does the same thing - it creates another type, just like above, except T is replaced with SomethingElse.
That's why you can't do this:
singleton.instance.UserID
Because the compiler doesn't know which type you're referring to. Is it the type it generated for singleton<main>, or is it the type generated for singleton<SomethingElse>? They're actually different types, which means the static properties - including UserID, will be different for each of them.
You could do this:
return data.GetUserFromID(singleton<main>.instance.UserID);
^^^^^^
...because now you're telling it the actual type - it's singleton<main>.
Just to clarify, unless the class has a private constructor and no non-private constructors, it isn't a singleton.
You can do this:
var mainSingleton = singleton<main>.instance;
and it will always return the same instance of main.
But you can also do this:
var m1 = new singleton<main>();
var m2 = new singleton<main>();
You can create multiple instances, so it's not a singleton. To fix this, add a private constructor to singleton:
private singleton() {}
Now the constructor can only be called from within the class. That means the only way to get an instance is to call instance. Every time you do that you'll get the same instance, so now it really is a singleton.
Is there an easy way to make an instance immutable?
Let's do an example, I have a class holding a lots of data fields (only data, no behavior):
class MyObject
{
// lots of fields painful to initialize all at once
// so we make fields mutable :
public String Title { get; set; }
public String Author { get; set; }
// ...
}
Example of creation:
MyObject CreationExample(String someParameters)
{
var obj = new MyObject
{
Title = "foo"
// lots of fields initialization
};
// even more fields initialization
obj.Author = "bar";
return obj;
}
But now that I have fully created my object, I don't want the object to be mutable anymore (because the data consumer will never need to change the state), so I would like something like that List.AsReadOnly:
var immutableObj = obj.AsReadOnly();
But if I want this behavior, I need to make another class that have exactly the same fields but without setter.
So is there any automatic way to generate this immutable class ? Or another way to allow mutability during creation but immutable once initialized ?
I know that fields can be marked as "readonly", but the object will be initialized outside of the class, and passing all fields as constructor parameters seems like a bad idea (too much parameters).
No, there is no easy way to make any type immutable, especially not if you want "deep" immutability (i.e. where no mutable object can be reached through the immutable object). You will have to explicitly design your types to be immutable. The usual mechanisms to make types immutable are these:
Declare (property-backing) fields readonly. (Or, starting with C# 6 / Visual Studio 2015, use read-only auto-implemented properties.)
Don't expose property setters, only getters.
In order to initialize (property-backing) fields, you must initialize them in the constructor. Therefore, pass the (property) values to the constructor.
Don't expose mutable objects, such as collections based on mutable-by-default types (like T[], List<T>, Dictionary<TKey,TValue>, etc.).
If you need to expose collections, either return them in a wrapper that prevents modification (e.g. .AsReadOnly()), or at the very least return a fresh copy of the internal collection.
Use the Builder pattern. The following example is too trivial to do the pattern justice, because it's usually recommended in cases where non-trivial object graphs need to be created; nevertheless, the basic idea is something like this:
class FooBuilder // mutable version used to prepare immutable objects
{
public int X { get; set; }
public List<string> Ys { get; set; }
public Foo Build()
{
return new Foo(x, ys);
}
}
class Foo // immutable version
{
public Foo(int x, List<string> ys)
{
this.x = x;
this.ys = new List<string>(ys); // create a copy, don't use the original
} // since that is beyond our control
private readonly int x;
private readonly List<string> ys;
…
}
Hmm I will enumerate my first thought on this...
1. Use internal setters if your only worry is manipulation outside of your assembly. internal will make your properties available to classes in the same assembly only. For example:
public class X
{
// ...
public int Field { get; internal set; }
// ...
}
2. I don't agree that it's necessarily a bad idea to have lots of parameters in your constructor.
3. You could generate another type at runtime that is a read-only version of your type. I can elaborate on this, but personally I think this is overkill.
Best, Iulian
As another solution you can use Dynamic Proxy. Alike approach was used for Entity Framework http://blogs.msdn.com/b/adonet/archive/2009/12/22/poco-proxies-part-1.aspx. Here is example how you can do it using Castle.DynamicProxy framework. This code is based on original example from Castle Dynamic proxy (http://kozmic.net/2008/12/16/castle-dynamicproxy-tutorial-part-i-introduction/)
namespace ConsoleApplication8
{
using System;
using Castle.DynamicProxy;
internal interface IFreezable
{
bool IsFrozen { get; }
void Freeze();
}
public class Pet : IFreezable
{
public virtual string Name { get; set; }
public virtual int Age { get; set; }
public virtual bool Deceased { get; set; }
bool _isForzen;
public bool IsFrozen => this._isForzen;
public void Freeze()
{
this._isForzen = true;
}
public override string ToString()
{
return string.Format("Name: {0}, Age: {1}, Deceased: {2}", Name, Age, Deceased);
}
}
[Serializable]
public class FreezableObjectInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
IFreezable obj = (IFreezable)invocation.InvocationTarget;
if (obj.IsFrozen && invocation.Method.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase))
{
throw new NotSupportedException("Target is frozen");
}
invocation.Proceed();
}
}
public static class FreezableObjectFactory
{
private static readonly ProxyGenerator _generator = new ProxyGenerator(new PersistentProxyBuilder());
public static TFreezable CreateInstance<TFreezable>() where TFreezable : class, new()
{
var freezableInterceptor = new FreezableObjectInterceptor();
var proxy = _generator.CreateClassProxy<TFreezable>(freezableInterceptor);
return proxy;
}
}
class Program
{
static void Main(string[] args)
{
var rex = FreezableObjectFactory.CreateInstance<Pet>();
rex.Name = "Rex";
Console.WriteLine(rex.ToString());
Console.WriteLine("Add 50 years");
rex.Age += 50;
Console.WriteLine("Age: {0}", rex.Age);
rex.Deceased = true;
Console.WriteLine("Deceased: {0}", rex.Deceased);
rex.Freeze();
try
{
rex.Age++;
}
catch (Exception ex)
{
Console.WriteLine("Oups. Can't change that anymore");
}
Console.WriteLine("--- press enter to close");
Console.ReadLine();
}
}
}
I would suggest having an abstract base type ReadableMyObject along with derived types MutableMyObject and ImmutableMyObject. Have constructors for all the types accept a ReadableMyObject, and have all the property setters for ReadableMyObject call an abstract ThrowIfNotMutable method before updating their backing field. Additionally, have ReadableMyObject support a public abstract AsImmutable() method.
Although this approach will require writing some boilerplate for each property of your object, that will be the extent of the required code duplication. The constructors for MutableMyObject and ImmutableMyObject will simply pass the received object to the base-class constructor. Class MutableMyObject should implement ThrowIfNotMutable to do nothing, and AsImmutable() to return new ImmutableMyObject(this);. Class ImmutableByObject should implement ThrowIfNotMutable to throw an exception, and AsImmutable() to return this;.
Code which receives a ReadableMyObject and wants to persist its contents should call its AsImmutable() method and store the resulting ImmutableMyObject. Code which receives a ReadableMyObject and wants a slightly-modified version should call new MutableMyObject(theObject) and then modify that as required.
You kind of hinted at a way in your question, but I'm not sure if this is not an option for you:
class MyObject
{
// lots of fields painful to initialize all at once
// so we make fields mutable :
public String Title { get; protected set; }
public String Author { get; protected set; }
// ...
public MyObject(string title, string author)
{
this.Title = title;
this.Author = author;
}
}
Due to the constructor being the only way of manipulating your Author and Title, the class is in effect immutable after construction.
EDIT:
as stakx mentioned, I too am a big fan of using builders - especially because it makes unit testing easier. For the above class you could have a builder such as:
public class MyObjectBuilder
{
private string _author = "Default Author";
private string _title = "Default title";
public MyObjectBuilder WithAuthor(string author)
{
this._author = author;
return this;
}
public MyObjectBuilder WithTitle(string title)
{
this._title = title;
return this;
}
public MyObject Build()
{
return new MyObject(_title, _author);
}
}
This way you can construct your objects with default values, or override them as you please, but MyObject's properties can't be changed after construction.
// Returns a MyObject with "Default Author", "Default Title"
MyObject obj1 = new MyObjectBuilder.Build();
// Returns a MyObject with "George R. R. Martin", "Default Title"
MyObject obj2 = new MyObjectBuilder
.WithAuthor("George R. R. Martin")
.Build();
If you ever need to add new properties to your class, it's much easier to go back to your unit tests that consume from a builder rather than from a hardcoded object instantiation (i don't know what to call it, so pardon my terms).
Well, if you have too many parameters and you dont want to do constructors with parameters....here is an option
class MyObject
{
private string _title;
private string _author;
public MyObject()
{
}
public String Title
{
get
{
return _title;
}
set
{
if (String.IsNullOrWhiteSpace(_title))
{
_title = value;
}
}
}
public String Author
{
get
{
return _author;
}
set
{
if (String.IsNullOrWhiteSpace(_author))
{
_author = value;
}
}
}
// ...
}
Here's another option. Declare a base class with protected members and a derived class that redefines the members such that they are public.
public abstract class MyClass
{
public string Title { get; protected set; }
public string Author { get; protected set; }
public class Mutable : MyClass
{
public new string Title { get { return base.Title; } set { base.Title = value; } }
public new string Author { get { return base.Author; } set { base.Author = value; } }
}
}
Creating code will use the derived class.
MyClass immutableInstance = new MyClass.Mutable { Title = "Foo", "Author" = "Your Mom" };
But for all cases where immutability is expected, use the base class:
void DoSomething(MyClass immutableInstance) { ... }
Given extension method below:
public static class Ext
{
public static void Serialize(this Guid guid_, StringWriter sw_)
{
sw_.Write(guid_.ToString("B"));
}
}
and the class:
public class Field<T>
{
public T value;
public void Serialize(StringWriter sw_)
{
value.Serialize(sw_);
}
}
I would like to do the following, but can't quite figure it out:
public class Foo
{
public Field<Guid> uid;
public Foo()
{
// assume StringWriter object sw;
uid.Serialize(sw);
}
}
Obviously real-life situation is more complicated, this is just a bare-bones example.
EDIT
Compiler errors:
error CS1928: 'T' does not contain a definition for 'Serialize' and the best extension method overload 'Ext.Serialize(System.Guid, StringWriter)' has some invalid arguments
error CS1929: Instance argument: cannot convert from 'T' to 'System.Guid'
It is not possible because T is not certainly known at compile time whether it is Guid or not.
But you can do something like this
public class GuidField : Field<Guid>
{
public override void Serialize(StringWriter sw_)//Assume we have made base class method virtual
{
value.Serialize(sw_);
}
}
This works, since c# compiler knows value is Guid at compile time.
Following way will work but it will defeat the point of "Generics". Not recommended also.
To show how to do I give an example
public void Serialize(StringWriter sw_)
{
if (typeof (T) == typeof (Guid))
{
((Guid)(object)value).Serialize(sw_);
}
}
There is no way to apply a restriction such that "T will only be of type that have extension methods defined for".
If you really need to use generics for this, you'll have to create an adapter for each type that can be serialized, as such:
public static class Ext
{
public static void Serialize(this Guid guid_, StringWriter sw_)
{
sw_.Write(guid_.ToString("B"));
}
}
public class Field<T> where T: ISerializableField
{
public T value;
public void Serialize(StringWriter sw_)
{
value.Serialize(sw_);
}
}
public interface ISerializableField
{
void Serialize(StringWriter sw);
}
public class SerializableGuid : ISerializableField
{
private readonly Guid _guid;
public SerializableGuid(Guid guid)
{
_guid = guid;
}
public void Serialize(StringWriter sw)
{
_guid.Serialize(sw);
}
}
This adapter wraps an instance of a given type and exposes a way to serialize it.
Notice that T in Field<T> now only works with instances of the adapter ISerializableField - Now Field<T> knows for sure that all instances of T can be serialized.
On that note, you wouldn't need the extension method anymore, the adapter could perform the serialization itself. Unless other parts of your code will also want to serialize a guid.
Edit
If avoiding creating a class for each type that can be serialized is your top priority, and you don't mind losing type safety, you can use dynamic invokation:
public class Field
{
private dynamic Value { get; set; }
public void Serialize(StringWriter sw)
{
try
{
Value.Serialize(sw);
}
catch (RuntimeBinderException ex)
{
throw new InvalidOperationException(string.Format("Instance of type {0} does not implement a Serialize method", Value.GetType()), ex);
}
}
}
No need for generics anymore. Generics enforce type safety and we're throwing that away.
I guess you are going to write a bunch of extension(Serializers) methods for every type. It's possible, but with some reflection magic.
public static class Ext
{
public static void Serialize(this Guid guid_, StringWriter sw_)
{
sw_.Write(guid_.ToString("B"));
}
public static void Serialize(this int id, StringWriter sw_)
{
sw_.Write(id.ToString());
}
}
public class Field<T>
{
public T value;
private static Lazy<Action<T, StringWriter>> _serializer = new Lazy<Action<T, StringWriter>>(() => (Action<T, StringWriter>)Delegate.CreateDelegate(typeof(Action<T, StringWriter>), typeof(Ext), "Serialize"), true);
public void Serialize(StringWriter sw_)
{
_serializer.Value(value, sw_);
}
}
the problem in your Field class is, T is a generic type and it, at this point, is "unknown" thus the extension method will not be shown as the extension method is of a concrete type for GUID.
you would maybe need to check to see if T is of guid and if so, do the cast to GUID which will then allow you to call the extension method - so not sure that it would even compile.
as for your last example in class Foo - is uid a GUID? if so did you import the project and namespace where your Ext class exists? if not - you should then it will show up.
A co-worker of mine asked me last week if it were possible in C# to extend a generic class from its generic parameter. He said it was possible in C++.
What he wanted makes actually sense. He wanted a generic decorator to annotate an arbitrary class with additional information. Something like:
public class Decorator<T> : T
{
public object AdditionalInformation {get:set;}
}
So that he can now use this generic decorator everywhere instead of T.
The most similar thing I could come with was a container class with the original object, the additional information and an implicit conversion.
public class Decorator<T>
{
private readonly T _instance;
public Decorator(T instance)
{
_instance = instance;
}
public T Instance
{
get { return _instance; }
}
public object AdditionalInformation { get; set; }
public static implicit operator T(Decorator<T> deco)
{
return deco._instance;
}
}
But this is not the same because the implicit conversion is only one way. He cannot use it, for example, as a return type of a method because the additional information would be lost after he implicit conversion.
Does anybody have a better idea?
If you can derive all decorable classes from some base class, then you can try to store decorators in that base class and make its info recoverable. Here is sample code that is guaranteed to contain some errors, but you can get the idea.
public class Decorable
{
Dictionary<Type,object> decors = new Dictionary<Type,object>();
public void AddDecorator<D>(D decor) { decors[typeof(D)] = decor; }
public D GetDecorator<D>()
{
object value;
if (decors.TryGetValue(typeof(D), out value))
return (D)value;
else
return default(D);
}
}
public class Decorator<T> where T: class, Decorable
{
private readonly T _instance;
public Decorator(T instance)
{
_instance = instance;
instance.AddDecorator(this);
}
public T Instance
{
get { return _instance; }
}
public object AdditionalInformation { get; set; }
}
// use it like this
Decorator<MyClass> myDecor = myObj.GetDecorator<Decorator<MyClass>>();
If you cannot derive, then you must store info in some static class. But, as wcoenen commented, you would need to clear that info or you'd get memory leaks. Clearing is error prone and not always possible, so it's better to go with the first approach. For example (not thread safe, you must add locking if you plan to use it in multithreaded apps):
static public class Decorators
{
static Dictionary<object,Dictionary<Type,object>> instance = new Dictionary<object,Dictionary<Type,object>>();
public static void AddDecorator<T,D>(this T obj, D decor)
{
Dictionary<Type,object> d;
if (!instance.TryGetValue(obj, out d))
{
d = new Dictionary<Type,object>();
instance.Add(obj, d);
}
d[typeof(D)]=decor;
}
public static D GetDecorator<T,D>(this T obj)
{
// here must be double TryGetValue, but I leave it to you to add it
return (D) instance[obj][typeof(D)];
}
public static T ClearDecorators(this T obj) { instance.remove(obj); }
}
// Decorator<T> code stays the same, but without type constraint
Why does the first constructor in ClassA cause the compiler error 'cannot use "this" in member intializer'?
... or how can i get this to work?
Thanks
public sealed class ClassA : IMethodA
{
private readonly IMethodA _methodA;
public ClassA():this(this)
{}
public ClassA(IMethodA methodA)
{
_methodA = methodA;
}
public void Run(int i)
{
_methodA.MethodA(i);
}
public void MethodA(int i)
{
Console.WriteLine(i.ToString());
}
}
public interface IMethodA
{
void MethodA(int i);
}
You are allowed to use the this(...) syntax to invoke another constructor at the same level - however, you cannot use this (the current instance) in this context.
The easiest option here is to duplicate the assignment code (_methodA = methodA).
Another option might be null-coalescing:
public ClassA():this(null)
{}
public ClassA(IMethodA methodA)
{ // defaults to "this" if null
_methodA = methodA ?? this;
}
This is called out in section 10.11.1 of the C# spec
An instance constructor initializer
cannot access the instance being
created. Therefore it is a
compile-time error to reference this
in an argument expression of the
constructor initializer, as is it a
compile-time error for an argument
expression to reference any instance
member through a simple-name.
There is no way to get this to work with an instance constructor because this cannot be accessed. What you could do is make the constructor private, create an initialization method and a static constructor.
public sealed class ClassA : IMethodA {
private ClassA() { }
private void Initialize(IMethodA param) { ... }
public static ClassA Create() {
var v1 = new ClassA();
v1.Initialize(v1);
return v1;
}
public static ClassA Create(IMethodA param) {
var v1 = new ClassA();
v1.Initialize(param);
return v1;
}
}
You're trying to pass the object before it is constructed. Although the compiler could do something sensible in this case, in general that won't work.
Your actual example works if you just do this:
public ClassA()
{
_methodA = this;
}
But you probably want to share more logic, so just use a function.
public ClassA()
{
SetStuff();
_methodA = this;
}
public ClassA(IMethodA methodA)
{
SetStuff();
_methodA = methodA;
}
You can't use the this keyword when chaining constructors essentially because this refers to an object that hasn't been instantiated yet (creation of the object doesn't begin until some (the top-level or base) constructor block has been entered). Moreover, why exactly would you want to do this? It seems rather pointless when you have access to the this keyword everywhere.
I recommend simply using independent constructors as such:
public sealed class ClassA : IMethodA
{
private readonly IMethodA _methodA;
public ClassA()
{
_methodA = this;
}
public ClassA(IMethodA methodA)
{
_methodA = methodA;
}
}
Perhaps I misunderstand what you're trying to do, but hopefully that will solve the issue for you.