Extension Methods and generics - How should I be doing this? - c#

I'm in the middle of overhauling some code and I hit a bit of a snag.
This is the method which I currently have, it needs reworking to support some structure changes:
/// <summary>
/// Recreates a dashboard control based off of its settings.
/// </summary>
/// <typeparam name="T"> The type of control to be recreated. </typeparam>
/// <param name="settings"> The known settings needed to recreate the control.</param>
/// <returns> The recreated control. </returns>
public static T Recreate<T>(ISetting<T> settings) where T : new()
{
T _control = new T();
settings.SetSettings(_control);
Logger.DebugFormat("Recreated control {0}", (_control as Control).ID);
return _control;
}
ISetting is being removed completely in favor of an extension method known to _control.
So, I have now:
public static class RadControlExtensions
{
public static RadDockZoneSetting GetSettings(this RadDockZone dockZone)
{
RadDockZoneSetting radDockZoneSetting = new RadDockZoneSetting(dockZone.UniqueName, dockZone.ID, dockZone.Skin, dockZone.MinHeight,
dockZone.HighlightedCssClass, dockZone.BorderWidth, dockZone.Parent.ID);
return radDockZoneSetting;
}
public static RadTabSetting GetSettings(this RadTab tab, int index)
{
RadTabSetting radTabSetting = new RadTabSetting(tab.Text, tab.Value, index);
return radTabSetting;
}
//Continued
}
The control that is being recreated is guaranteed to have this extension method (would be nice to enforce this, though.)
I'm now at:
public static T Recreate<T>() where T : new()
{
T _control = new T();
//Not right -- you can't cast a control to an extension method, obviously, but
//this captures the essence of what I would like to accomplish.
(_control as RadControlExtension).SetSettings();
Logger.DebugFormat("Recreated control {0}", (_control as Control).ID);
return _control;
}
What should I be looking into to support this, if possible?

If you know that every _control that gets passed will be a RadDockZone (or derived from RadDockZone) just do this:
T _control = new T();
(RadDockZone)_control.SetSettings();
Logger.DebugFormat("Recreated control ... //rest of code here
If it's not always going to be a RadDockZone, you'll need to do some type checking to get the right type to call the extension method. I'm presuming, there, that you have a .SetSettings() extension method on all the possible Types that could be passed to your Recreate method.

You need to cast your T to something that is supported by your extension method.
(_control as RadDockZone).GetSettings
Extension methods operate on a type they are not a type in the traditional sense. The 'SomeFn(string this)' makes your extension work on things that are strings which would be strings and anything derived from them.

If I understand correctly what you are trying to do, just put a constraint on T:
public static T Recreate<T>() where T : RadControl, new() {
// etc.
}
You might have to use double dispatch and define
public static RadControl GetSettings(this RadControl control) {
}
which will invoke the appropriate GetSettings method.

No, Jason's answer is the cleaner way to go. The accepted solution killed the type safety and made use of generics pointless. You could switch to generic-less design (having a RadControlFactory) and had the job done.

Related

Static generic delegate field in C#

Using generic types is nice and easy, but since I tried to implement my own generic types, I came to a problem which I couldn't solve by myself yet. I want to have a static field for a delegate. This is how it works for me when using non-generic types:
delegate Type Type_Delegate(Type type);
static Type_Delegate TypeMethod = new Type_Delegate(TypeMethodName);
// Now the TypeMethod can be called like this from somewhere in the Code:
ClassName.TypeMethod(typeof(string));
But when using any generic type:
delegate T Type_Delegate<T>(T type);
// This static field syntax isn't allowed:
static Type_Delegate<T> TypeMethod = new Type_Delegate<T>(TypeMethodName);
// It would be a dream to be able to use it like this now:
ClassName.TypeMethod<string>("Hello world!");
T is unknown type/namespace.
When I experiment with the syntax:
// This static field syntax isn't allowed, too:
static Type_Delegate TypeMethod = new Type_Delegate(TypeMethodName);
Type arguments are missing for usage.
I tried several ideas about the possible syntax, but not succeed...
How do I need to change the static field syntax to work as assumed, so the code is able to set a generic delegate method as value, without having to specify a type at that time?
Edit: I also tried to wrap the delegate and field with a generic static class, but there I still have the same syntax issues, when I want to set the field value without specifying the type.
Edit 2: Maybe the following example workaround apporach will clarify my thoughts more, since I think most commenters didn't understand my goal (maybe it's my bad English, too):
using System;
using System.Linq;
using System.Reflection;
namespace Testing
{
public static class GenericTest
{
public interface IGenericClass<T>
{
T Method(T parameter);
}
public class GenericClass<T> : IGenericClass<T>
{
public T Method(T parameter)
{
// Just a stupid example, don't think about that...
return parameter;
}
}
/// <summary>
/// The value must be any type that implements the IGenericClass<T> interface
/// </summary>
public static Type GenericField = typeof(GenericClass<>);
/// <summary>
/// Call the method of an instance of the type that was set to GenericField
/// </summary>
/// <param name="T">The type to use for creating an instance of the generic class</param>
/// <param name="parameter">The parameter for calling the method of the generic class</param>
/// <returns>Any value of type "T"</returns>
public static dynamic GenericMethod(Type T, object parameter)
{
var genericType = GenericField.MakeGenericType(new Type[] { T });
MethodInfo method = genericType.GetMethod("Method");
if (method == null) throw new InvalidCastException("GenericField isn't a IGenericClass<T> type");
return method.Invoke(Activator.CreateInstance(genericType), new object[] { parameter });
}
}
}
Now I can do something like this somewhere else in the code:
MessageBox.Show(Testing.GenericTest.GenericMethod(typeof(string), "Hello world!"));
In this example solution I need to work with classes and an interface, require reflections, it's a whole bunch of code required to get the same functionality for a generic (class-)method, as I can get with only two lines of code when working with non-generic methods (using delegates). What an overhead, what a hack - I try to avoid doing such nasty things in productive code. But if there are no better 2 lines of Code that do the same, this time I will have to fight my ego...
It is possible, by wrapping it in a generic class definition and using the class type parameter.
static class C<T>
{
public static DelegateTypePrototype<T> DelegateType;
}
This way the type only has to be resolved once you "request" an instance of the class. At least that's my intuitive understanding coming from C++ templates background.

Cast dynamic to type through external static extension call stays dynamic

I have a strange behaviour.
I use the following method to cast any object to any given type.
using System.Dynamic;
...
/// <summary>
/// Casts any object to passed type.
/// </summary>
/// <typeparam name="T">Wished type</typeparam>
/// <param name="obj">The object you want to be casted.</param>
public static T ToType<T>(this object obj) => (T)obj;
For example (object to dynamic):
AnyLabel.Tag = new ExpandoObject();
AnyLabel.Tag.ToType<dynamic>().Item2 = new Form(); // works
Now following situation (dynamic to typed object):
// var is NOT from type form, why?:
var form = ToType<Form>(AnyLabel.Tag.ToType<dynamic>().Item2);
// the other way works like desired:
var form2 = ((Form)AnyLabel.Tag.ToType<dynamic>().Item2);
I can not access any form properties/methods using the casting extension à la:
ToType<Form>(AnyLabel.Tag.ToType<dynamic>().Item2).Show();
My question is, why is the first var not from type form and denies me the last code part to execute?
The method ToType<T>() could have overloaded versions. If no dynamics are involved, the compiler resolves the right overload at compile time. If; however, dynamics are involved, the binding happens at runtime, i.e., the right overload is determined at runtime using the runtime type of the arguments. Also, these overloads could have different return types. Since now, this return type is not known at compile time, the C# compiler decides to choose dynamic as return type of your function.
Now, you could reason, that you don't have an overloaded version and that Form could safely be assumed. But what happens, if you add overloads later? Should this suddenly change the return type of an expression that did not change? Adding an overload, would introduce a breaking change to existing code that cannot be detected at compile time.
Which return type to choose at compile time, if overload is determined by runtime argument type?
public static T ToType<T>(this object obj) => (T)obj;
public static int ToType<T>(this int i) => i; // Makes no sense, but valid code.
public static dynamic ToType<T>(this dynamic d) => d; // Valid as well.

How to create an empty IReadOnlyCollection

I'm creating an extension method for MultiValueDictionary to encapsulate frequent ContainsKey checks and I was wondering what was the best way to create an empty IReadOnlyCollection?.
What I've used so far is new List<TValue>(0).AsReadOnly() but there must be a better way, an equivilant to IEnumerable's Enumerable.Empty
public static IReadOnlyCollection<TValue> GetValuesOrEmpty<TKey, TValue>(this MultiValueDictionary<TKey, TValue> multiValueDictionary, TKey key)
{
IReadOnlyCollection<TValue> values;
return !multiValueDictionary.TryGetValue(key, out values) ? new List<TValue>(0).AsReadOnly() : values;
}
EDIT: The new .Net 4.6 adds an API to get an empty array: Array.Empty<T> and arrays implement IReadOnlyCollection<T>. This also reduces allocations as it only creates an instance once:
IReadOnlyCollection<int> emptyReadOnlyCollection = Array.Empty<int>();
What I ended up doing is mimicking the implementation of Enumerable.Empty using new TElement[0]:
public static class ReadOnlyCollection
{
public static IReadOnlyCollection<TResult> Empty<TResult>()
{
return EmptyReadOnlyCollection<TResult>.Instance;
}
private static class EmptyReadOnlyCollection<TElement>
{
static volatile TElement[] _instance;
public static IReadOnlyCollection<TElement> Instance
{
get { return _instance ?? (_instance = new TElement[0]); }
}
}
}
Usage:
IReadOnlyCollection<int> emptyReadOnlyCollection = ReadOnlyCollection.Empty<int>();
return new List<XElement>().AsReadOnly();
I don't think there's anything like Enumerable.Empty for read-only collections, but:
List<T> already implements IReadOnlyCollection<T> so you can avoid one object allocation by not calling AsReadOnly() and simply casting the list instead. This is less "safe" in theory but hardly matters in practice.
Alternatively, you could cache the returned ReadOnlyCollection to avoid any object allocation whatsoever (except for the cached object).
As far as I know there is no built in way(Interested to know if one). That said, you can use the following:
IReadOnlyCollection<TValue> readonlyCollection = new ReadOnlyCollection<TValue>(new TValue[] { });
Optionally you can cache the results as it is a ReadOnlyCollection over empty array, It will always be the same no matter how many instances you have.
How's about this which has a similar syntax to Enumerable.Empty:
/// <summary>
/// Contains a method used to provide an empty, read-only collection.
/// </summary>
public static class ReadOnlyCollection
{
/// <summary>
/// Returns an empty, read-only collection that has the specified type argument.
/// </summary>
/// <typeparam name="T">
/// The type to assign to the type parameter of the returned generic read-only collection.
/// </typeparam>
/// <returns>
/// An empty, read-only collection whose type argument is T.
/// </returns>
public static IReadOnlyCollection<T> Empty<T>()
{
return CachedValueProvider<T>.Value;
}
/// <summary/>
static class CachedValueProvider<T>
{
/// <summary/>
public static readonly IReadOnlyCollection<T> Value = new T[0];
}
}
Used like this:
IReadOnlyCollection<int> empty = ReadOnlyCollection.Empty<int>();

Activator.CreateInstance and Ninject

I have a project I'm working on where I don't know what class I will need to instantiate at compile time. I'm trying to use Activator.CreateInstance() to generate a new class for me based on the user input. The code below works well, but I had to change my constructor on my INECCQuery classes to only have a default constructor and not use any sort of dependency injection. Is there a way I can still use my injection bindings and the Activator.CreatInstance()? I'm using Ninject for injection.
[HttpGet]
public ActionResult Index(string item) {
Type t = Type.GetType(string.Format("Info.Audit.Query.{0}Query, Info.Audit", item.ToUpper()));
if (t != null) {
INECCQuery query = (INECCQuery)Activator.CreateInstance(t);
var results = query.Check();
return View("Index", results);
}
return View("Notfound");
}
Constructor injection is always preferred where possible, but a suitable backup would be to leverage property injection.
http://ninject.codeplex.com/wikipage?title=Injection%20Patterns
class SomeController {
[Inject]
public Object InjectedProperty { get; set; }
}
Based on the assumption that you are trying to replace the Activator.CreateInstance you can inject a Func<T, INECCQuery> or whatever factory you wish to use.
You can get Ninject to give you an object of type t at runtime and still get the dependency injection via the constructor.... I do something similar for one case within my application.
In the Global.asax.cs file, I have the following method:
/// <summary>
/// Gets the instance of Type T from the Ninject Kernel
/// </summary>
/// <typeparam name="T">The Type which is requested</typeparam>
/// <returns>An instance of Type T from the Kernel</returns>
public static T GetInstance<T>()
{
return (T)Kernel.Get(typeof(T));
}
This depends on a static Kernel reference.
Then, in code, I do
var myInfrastructureObject = <YourAppNameHere>.GetInstance<MyInfrastructureType>();
So, I know the type at compile time whereas you don't, but it wouldn't be that difficult to change that.
You may also wish to look into the ServiceLocator Pattern.
I've actually found out you can just pass in a second option to the Activator.CreateInstance method and as long as it matches your constructors signature it will work. The only problem is if your parameters don't match you will get a runtime error.
Type t = Type.GetType(string.Format("Info.Audit.Query.{0}Query, Info.Audit", item.ToUpper()));
INECCQuery query = (INECCQuery)Activator.CreateInstance(t, repository);
Thanks for all the help.

protobuf-net inheritance

Marc mentioned on stackoverflow that it will be possible in v2 of protobuf-net to use ProtoInclude attribute (or similar approach) to serialize/deserialize class hierarchy without a need to specify each subtype in the base class. Is this implemented yet? We have a plugin interface that can be derived in external libraries, so there is no way of knowing what the derived types will be. We could maintain unique numbering between types though, but I couldn’t find any examples on the net, short of using ProtoInclude attribute which requires a subtype to be specified.
How would I go about implementing inheritance with protobuf-net like that if I don't know what the subtypes are?
If you can't specify the subtypes in attributes (because it isn't known at compile-time) you have 2 options (both of which only apply to "v2", available as beta):
use a RuntimeTypeModel, rather than the static Serializer methods (which are now just a short-cut to RuntimeTypeModel.Default); tell the model about the inheritance (example below)
add DynamicType = true to the [ProtoMember(...)] in question
The second is not very pure protobuf - it embeds type information, which I don't really love but people just kept asking for. The first is my preferred option. To add subtypes at runtime:
var model = TypeModel.Create();
var type = model.Add(typeof(YourBaseType), true);
var subTypeA = model.Add(typeof(SomeSubType), true);
var subTypeB = model.Add(typeof(SomeOtherSubType), true);
type.AddSubType(4, typeof(SomeSubType));
type.AddSubType(5, typeof(SomeOtherSubType));
the true in the above means "use normal rules to add member properties automatically" - you can also take control of that and specify the properties (etc) manually if you prefer.
Note that a TypeModel should be cached and re-used (not created per object you need to serialize), as it includes some "emit" code to generate methods. Re-using it will be faster and require less memory. The type-model is thread-safe, and can be used to serialize/deserialize multiple streams concurrently on different threads.
To further expand Marc's answer, specifically dealing with RuntimeTypeModel, this is one way to write it:
RuntimeTypeModel.Default[typeof(BaseClass)].AddSubType(20, typeof(DerivedClass));
If you have more classes derived from derived classes, link them like this
RuntimeTypeModel.Default[typeof(DerivedClass)].AddSubType(20, typeof(DerivedFromDerivedClass ));
And so on.
You can then use Serializer.Serialize(file,object), as you would normally with protobuf-net.
This works across projects and namespaces.
By adding helper extension method:
public static class RuntimeTypeModelExt
{
public static MetaType Add<T>(this RuntimeTypeModel model)
{
var publicFields = typeof(T).GetFields().Select(x => x.Name).ToArray();
return model.Add(typeof(T), false).Add(publicFields);
}
}
You can streamline sub-type registration like this:
private static RuntimeTypeModel CreateModel()
{
var model = TypeModel.Create();
model.Add<ExportInfo>();
model.Add<RegistrationInfo>();
model.Add<FactorySetupInfo>()
.AddSubType(101, model.Add<ServiceSetupInfo>().Type)
.AddSubType(102, model.Add<GenericWrapperSetupInfo>().Type)
.AddSubType(103, model.Add<DecoratorSetupInfo>().Type);
return model;
}
I solved this by completely flattening the hierarchy of fields for each ProtoContract. I also assume all fields will be serialized unless [ProtoIgnore] exists and therefore do not decorate fields with [ProtoMember(n)]. It does not need oneOf or [ProtoInclude]. This is what I use, no more scratching my head wondering what went wrong in the numbering etc. Feel free to expand on it to your needs.
A note: it takes any Type decorated with ProtoContract in an Assembly, flattens it's fields, ignores those with [ProtoIgnore], then automatically builds up all the ProtoMembers(n) (so no need for manual numbering).
It also accepts a single Generic Argument Protocol, where you supply the known Generic types e.g MyContract'1 and you supply typeof(MyContract2) such that the concreted type for serializing is MyContract<MyContract2>
Edit: This is a basic example and serves my needs. You may wish to extend it and sort the fields like so, so that you can manage adding new fields and retain backwards compat.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-member-order
To this end you could ignore Proto attributes entirely in the code and replace with DataContract, DataMember etc for discovery and let your contracts be both DataContracts and ProtoContracts with known ordering for both.
/// <summary>
/// <see cref="CompileProtocols(Assembly, Type[])"/>.
/// </summary>
/// <param name="knownGenericArguments"></param>
/// <returns></returns>
public static IEnumerable<Type> CompileProtocols(params Type[] knownGenericArguments)
{
var rv = CompileProtocols(Assembly.GetExecutingAssembly(), knownGenericArguments);
return rv;
}
/// <summary>
/// Compiles protocols that are non generic or take a single generic argument (`1). Single generic argument protocols
/// will be concreted against the knownGenericArguments passed into the method.
/// </summary>
/// <param name="genericArgumentTypes"></param>
public static IEnumerable<Type> CompileProtocols(Assembly inAssembly, params Type[] knownGenericArguments)
{
var runtimeProtocolTypes = new List<Type>();
var assemblyProtocolTypes =inAssembly.GetTypes().Where(t => t.GetCustomAttribute<ProtoContractAttribute>() != null);
foreach(var assemblyProtocolType in assemblyProtocolTypes)
{
if(assemblyProtocolType.IsGenericType == false)
{
runtimeProtocolTypes.Add(assemblyProtocolType);
}
else
{
if (knownGenericArguments.Length > 0)
{
var assemblyTypeGenericArgs = assemblyProtocolType.GetGenericArguments();
if (assemblyTypeGenericArgs.Length == 1)
{
foreach (var knownGenericArgument in knownGenericArguments)
{
var runtimeGenericType = assemblyProtocolType.MakeGenericType(knownGenericArgument);
runtimeProtocolTypes.Add(runtimeGenericType);
}
}
}
}
}
BuildModel(runtimeProtocolTypes);
return runtimeProtocolTypes;
}
/// <summary>
/// Builds and optionally compiles (default=true) the RuntimeTypeModel. In this case it uses the RumtimeTypeModel.Default
/// with a CompileInPlace.
///
/// Note: You might wish to change this to build another model or return a complete Compiled model instead.
/// </summary>
/// <param name="protocolTypes"></param>
/// <param name="compile"></param>
private static void BuildModel(IEnumerable<Type> protocolTypes, bool compile = true)
{
foreach (var protocolType in protocolTypes)
{
int index = 1;
var fields = protocolType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Where(f => f.GetCustomAttribute<ProtoIgnoreAttribute>() == null);
var metaType = RuntimeTypeModel.Default.Add(protocolType);
foreach (var field in fields)
{
metaType.AddField(index, field.Name);
index++;
}
}
if (compile)
{
RuntimeTypeModel.Default.CompileInPlace();
}
}

Categories