Controlling when the Static Constructor is called - c#

In my custom attribute's static constructor, I search the loaded assembly for all classes decorated with my attribute and perform some action on them.
I would like the static constructor to be called as soon as possible during runtime, preferably before execution of the static void Main() entry point.
Currently it only gets called after I make some call to the attribute. I could make such a call elsewhere in my program, but ideally the attribute's functionality would be self-contained.
Looking for answers, I read this on MSDN:
The user has no control on when the static constructor is executed in the program.
But surely there is some tricky, sly, or mischievous workaround to get a static constructor to be called ASAP. Perhaps an attribute, reflection, or some other kind of magic could be used. Can it be done?
Because people would undoubtedly tell me that there is no good reason to do what I ask, I present my purpose and my code: I am trying to use attributes to declaratively configure a db4o factory. If my attribute's static constructor is called after I've already established a connection, then it has no effect and is useless. Therefore it must be called before my program gets a chance to establish such a connection.
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
sealed public class CascadeOnUpdateAttribute : Attribute
{
public bool Flag { get; private set; }
public CascadeOnUpdateAttribute() : this(true) { }
public CascadeOnUpdateAttribute(bool flag)
{
Flag = flag;
}
static CascadeOnUpdateAttribute()
{
var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
from attribute in type.GetCustomAttributes(typeof(CascadeOnUpdateAttribute), false).Cast<CascadeOnUpdateAttribute>()
select new { Type = type, Cascade = attribute.Flag };
foreach (var target in targets)
{
Db4oFactory.Configure().ObjectClass(target.Type).CascadeOnUpdate(target.Cascade);
}
}
}
Update:
I ended up using an abstract attribute with a static method. This way I can derive as many attributes as I like and they will all be applied to a specified config by calling this one method.
public abstract class Db4oAttribute : Attribute
{
public abstract void Configure(IConfiguration config, Type type);
public static void ApplyAttributes(IConfiguration config)
{
var targets = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
from attribute in type.GetCustomAttributes(typeof(Db4oAttribute), false).Cast<Db4oAttribute>()
select new { Type = type, Attribute = attribute };
foreach (var target in targets)
{
target.Attribute.Configure(config, target.Type);
}
}
}
And the call site:
Db4oAttribute.ApplyAttributes(Db4oFactory.Configure());
_db = Db4oFactory.OpenFile("Test.db4o");

As Marc says, I would do it explicitly in Main if I were you.
You can invoke the type initializer for a type explicitly using the Type.TypeInitializer property and invoking it. However, this will cause it to run again even if it's already been run which could produce unexpected results.
I would personally move that code out of the static initializer completely. It's configuration code - why not just make it a static method which you can call explicitly? I'm not even sure I'd have it in the attribute class itself, but at least explicitly calling:
CascadeOnUpdateAttribute.ConfigureDb4oFactories();
is clearer than calling a dummy method or forcing type initialization some other way, just to get a side effect.

If you want the static constructor to get called, then add a dummy method to the type and simply call it at the start of your code (Main etc); if it is a trivial / empty method you might want to mark it for no inlining etc.
class SomeType {
static SomeType() {
Console.WriteLine("SomeType.cctor");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Init() { }
}
static class Program {
static void Main() {
SomeType.Init();
Console.WriteLine("hi");
}
}
You can use reflection to call the static constructor, but I don't recommend it; if you use reflection you can actually call the .cctor multiple times, and that is never a good thing...

You can avoid the static dummy method by calling
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(CascadeOnUpdateAttribute).TypeHandle)

I think the use of the static constructor smells; I would consider refactoring your code to control access to the db4o factory so that you don't need to use it.

Related

Provide extension method for types derived from `this` type

I've read this similar question I don't expect the same behavior as the OP and I don't really understand him but I have a usage for protected members inside the derived classes.
In Why is the 'this' keyword required to call an extension method from within the extended class Eric Lippert wrote:
... If you are in the scenario where you are using an extension method
for a type within that type then you do have access to the source
code. Why are you using an extension method in the first place then?
... Given those two points, the burden no longer falls on the language
designer to explain why the feature does not exist. It now falls on
you to explain why it should. Features have enormous costs associated
with them.
...
So I will try to explain why I would expect a behavior and it's usage example.
The feature:
A programer can access protected member of this object inside extension method.
When a protected member is used within extension method, you can only use the method inside classes derived from type of this object.
Protected extension method can be called only with this argument object which is the same object that is accessible by this keyword in caller method.
Real life usage scenario:
I'm playing with creating a Visual Studio custom editor based on WPFDesigner_XML example.
Currently I'm trying to figure things out in class with following signature:
public sealed class EditorPane : WindowPane, IOleComponent, IVsDeferredDocView, IVsLinkedUndoClient
{...}
Lot of methods are using services Like this:
void RegisterIndependentView(bool subscribe)
{
IVsTextManager textManager = (IVsTextManager)GetService(typeof(SVsTextManager));
if (textManager != null)
{
if (subscribe)
{
textManager.RegisterIndependentView(this, _textBuffer);
}
else
{
textManager.UnregisterIndependentView(this, _textBuffer);
}
}
}
I like to keep focus on things that actually matter so I wrote helper method to simplify such methods. For example:
private void RegisterIndependentView(bool subscribe) {
if (with(out IVsTextManager tm)) return;
if (subscribe) tm.RegisterIndependentView(this, _textBuffer);
else tm.UnregisterIndependentView(this, _textBuffer);
}
The with method look like this:
private bool with<T>(out T si) {
si = (T)GetService(getServiceQueryType<T>());
return si == null ? true : false;
}
And I placed getServiceQueryType<T>() in a static class:
public static class VSServiceQueryHelper {
public static Type getServiceQueryType<T>() {
var t = typeof(T);
if (!serviceQueryTypesMap.ContainsKey(t)) throw new Exception($#"No query type was mapped in ""{nameof(serviceQueryTypesMap)}"" for the ""{t.FullName}"" interface.");
return serviceQueryTypesMap[t];
}
private static Dictionary<Type, Type> serviceQueryTypesMap = new Dictionary<Type, Type>() {
{ typeof(IVsUIShellOpenDocument), typeof(SVsUIShellOpenDocument) },
{ typeof(IVsWindowFrame), typeof(SVsWindowFrame) },
{ typeof(IVsResourceManager), typeof(SVsResourceManager) },
{ typeof(IVsRunningDocumentTable), typeof(SVsRunningDocumentTable) },
{ typeof(IMenuCommandService), typeof(IMenuCommandService) },
{ typeof(IVsTextManager), typeof(SVsTextManager) },
};
}
This works well but I would also like to place the with method inside VSServiceQueryHelper as an extension so any time I would extend WindowsPane i could just place using static com.audionysos.vsix.utils.VSServiceQueryHelper; at the top and use the with method that is already implemented.
The problem:
I can't make with method an extension because the GetService method used by it is a protected member of the WindowsPane which is the base type of my class. So now I need to place with implementation in every class that extends WindowPane and this breaks the rule of never repeat yourself :/
A simple solution would be to create a base class containing the With method.
If that is too burdensome, then you can also implement this using Reflection to invoke the GetService method from the extension method. In fact, we can create a delegate to it that will ensure there is minimal overhead to invoking With many times.
internal static class WindowPaneExtensions
{
private static readonly Func<WindowPane, Type, object> WindowPaneGetService = CreateWindowPaneGetService();
public static bool With<T>(this WindowPane pane, out T service)
{
service = (T)WindowPaneGetService(pane, GetServiceQueryType<T>());
return service != null;
}
private static Func<WindowPane, Type, object> CreateWindowPaneGetService()
{
var method = typeof(WindowPane).GetMethod("GetService", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(Type) }, null);
var del = (Func<WindowPane, Type, object>)method.CreateDelegate(typeof(Func<WindowPane, Type, object>));
return del;
}
}
I think your proposal to allow certain extension methods access to protected members is a non-starter. For example, the following is not allowed:
public class MyPane : WindowPane
{
public static void Test(WindowPane p)
{
var service = p.GetService(typeof(Service));
// etc.
}
}
But you ask, "Isn't it allowed to access base class members from a derived class?" No, that actually isn't the rule. The rule is that you can access base class members from derived class only via a reference to the derived class, not from any base class reference directly. More details on this here. Your proposal amounts to allowing this kind of thing for an even larger class methods (i.e. methods that some other library author declares to be extension methods). Eric Lippert has written about this issue (here and here) in the past as well. Since cross hierarchy calls are blocked by the CLR, I would not expect something like this proposal to get implemented any time soon.

Is setting a static field via reflection guaranteed to call type initializer?

The following code sets the value of a static field and the initializer (static constructor) is called.
public class Foo
{
static Foo()
{
Console.WriteLine("Initialized");
}
public static string Bar;
}
static Program()
{
FieldInfo fld = typeof(Foo).GetField("Bar");
fld.SetValue(null, ""); // cctor gets called
}
Will this always happen; does setting a static field via reflection guarantee the static constructor will run if it hasn't already?
if you access any member of the class, the runtime will invoke the static constructor automatically for you.
Meaning that yes, the static constructor will run if it hasn't already, this is one of the advantages of reflection.
You do not have to initialize it directly, only access it's properties.
this will work as well:
Type myClass = typeof(MyClass);
myClass.GetField("SomeValue").GetValue(null);
If you do want to invoke it explicitly, you can use this:
myClass.TypeInitializer.Invoke(null, null);
Though it is not a good practice and not recommended, I would strongly recommend that you don't do this, however - it violates a type expecting the static constructor to only be executed once.

C# Access a static method that is hidden by a local property

I'm sure this must have been asked already, but I can't seem to find the answer. I need to know how to access a static method, when the class it is defined within has been hidden by an instance method with the same name.
I have a class which exposes a static method as follows:
public class Plan
{
public static Plan Generate(Project project)
{
var plan = new Plan();
// ...
return plan;
}
}
I then have another class which contains a method called "Plan", from which I want to call the static method mentioned above:
public ActionResult Plan(int id)
{
// ...
var plan = Plan.Generate(project);
// ...
}
The problem is that the class name 'Plan' is hidden by the method name, so I cannot call the static method directly.
Qualify your access to the Plan type with the type's name. For example:
YourNamespace.Plan.Generate
That said, static methods are bad mkay. Make yourself an IPlanFactory, bind PlanFactory to it and let dependency injection do the rest (assuming you're using constructor injection and not that hairbrained dependency resolver stuff). Now it's unambigiously _planFactory.Generate(...) and you've just increased testability. Give yourself a raise!

How to construct a call to a method using dynamic

Hi I have a namespace with a lot of classes and all of them has a method Destroy(int id)
I want to call that method using dynamic word.
Here is my example:
public bool DeleteElement<T>(T tElement)
{
Type t = typeof(T);
dynamic element = tElement;
var id = element.Id;
//until here everything is fine
//here I want to say
(namespace).myClassName.Destroy(id);
//the name of myClassName is like t.ToString()
}
I can avoid namespace including a using at the top. The idea is to call that static method using dynamic, not Reflection, please see that Destroy is a static method of T. I need something like this T.Destroy(id)
If Destroy(int id) is a static method, couldn't you create an instance method that would call the static one?
public void Destroy()
{
ThisClass.Destroy(this.Id);
}
You could then define an IDestroyable interface implemented by all these classes:
interface IDestroyable { void Destroy(); }
And then modify your DeleteElement method as follows:
public bool DeleteElement<T>(T tElement) where T : IDestroyable
{
tElement.Destroy();
}
No need to use dynamic here... Actually, using dynamic in this situation is often an indication of bad design. It's quite rare to actually need dynamic except in the scenarios for which it was created (e.g. interop with dynamic languages)
(If the classes are generated but they have the partial modifier, you can declare the new method in another file that is not touched by the generator)
EDIT: if the classes are generated and are not partial, you can't modify them... So another solution would be to use reflection; I know you want to avoid that (for performance reasons I assume), but you can limit the performance impact by doing the reflection only once for each type: you just need to create and cache a delegate for each type.
class DestroyHelper<T>
{
static readonly Action<int> _destroy;
static readonly Func<T, int> _getId;
static DestroyHelper()
{
var destroyMethod = typeof(T).GetMethod("Destroy", BindingFlags.Static | BindingFlags.Public);
_destroy = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), destroyMethod);
var getIdMethod = typeof(T).GetProperty("Id").GetGetMethod();
_getId = (Func<T, int>)Delegate.CreateDelegate(typeof(Func<T, int>), getIdMethod);
}
public static void Destroy(T element)
{
_destroy(_getId(element));
}
}

Member '<member name>' cannot be accessed with an instance reference

I am getting into C# and I am having this issue:
namespace MyDataLayer
{
namespace Section1
{
public class MyClass
{
public class MyItem
{
public static string Property1{ get; set; }
}
public static MyItem GetItem()
{
MyItem theItem = new MyItem();
theItem.Property1 = "MyValue";
return theItem;
}
}
}
}
I have this code on a UserControl:
using MyDataLayer.Section1;
public class MyClass
{
protected void MyMethod
{
MyClass.MyItem oItem = new MyClass.MyItem();
oItem = MyClass.GetItem();
someLiteral.Text = oItem.Property1;
}
}
Everything works fine, except when I go to access Property1. The intellisense only gives me "Equals, GetHashCode, GetType, and ToString" as options. When I mouse over the oItem.Property1, Visual Studio gives me this explanation:
MemberMyDataLayer.Section1.MyClass.MyItem.Property1.getcannot be accessed with an instance reference, qualify it with a type name instead
I am unsure of what this means, I did some googling but wasn't able to figure it out.
In C#, unlike VB.NET and Java, you can't access static members with instance syntax. You should do:
MyClass.MyItem.Property1
to refer to that property or remove the static modifier from Property1 (which is what you probably want to do). For a conceptual idea about what static is, see my other answer.
You can only access static members using the name of the type.
Therefore, you need to either write,
MyClass.MyItem.Property1
Or (this is probably what you need to do) make Property1 an instance property by removing the static keyword from its definition.
Static properties are shared between all instances of their class, so that they only have one value. The way it's defined now, there is no point in making any instances of your MyItem class.
I had the same issue - although a few years later, some may find a few pointers helpful:
Do not use ‘static’ gratuitously!
Understand what ‘static’ implies in terms of both run-time and compile time semantics (behavior) and syntax.
A static entity will be automatically constructed some time before
its first use.
A static entity has one storage location allocated, and that is
shared by all who access that entity.
A static entity can only be accessed through its type name, not
through an instance of that type.
A static method does not have an implicit ‘this’ argument, as does an
instance method. (And therefore a static method has less execution
overhead – one reason to use them.)
Think about thread safety when using static entities.
Some details on static in MSDN:
Static Classes in C#
Static Constructors in C#
This causes the error:
MyClass aCoolObj = new MyClass();
aCoolObj.MyCoolStaticMethod();
This is the fix:
MyClass.MyCoolStaticMethod();
Explanation:
You can't call a static method from an instance of an object. The whole point of static methods is to not be tied to instances of objects, but instead to persist through all instances of that object, and/or to be used without any instances of the object.
No need to use static in this case as thoroughly explained. You might as well initialise your property without GetItem() method, example of both below:
namespace MyNamespace
{
using System;
public class MyType
{
public string MyProperty { get; set; } = new string();
public static string MyStatic { get; set; } = "I'm static";
}
}
Consuming:
using MyType;
public class Somewhere
{
public void Consuming(){
// through instance of your type
var myObject = new MyType();
var alpha = myObject.MyProperty;
// through your type
var beta = MyType.MyStatic;
}
}
cannot be accessed with an instance reference
It means you're calling a STATIC method and passing it an instance. The easiest solution is to remove Static, eg:
public static void ExportToExcel(IEnumerable data, string sheetName)
{
Remove the static in the function you are trying to call. This fixed the problem for me.
I got here googling for C# compiler error CS0176, through (duplicate) question Static member instance reference issue.
In my case, the error happened because I had a static method and an extension method with the same name. For that, see Static method and extension method with same name.
[May be this should have been a comment. Sorry that I don't have enough reputation yet.]
I know this is an old thread, but I just spent 3 hours trying to figure out what my issue was. I ordinarily know what this error means, but you can run into this in a more subtle way as well. My issue was my client class (the one calling a static method from an instance class) had a property of a different type but named the same as the static method. The error reported by the compiler was the same as reported here, but the issue was basically name collision.
For anyone else getting this error and none of the above helps, try fully qualifying your instance class with the namespace name. ..() so the compiler can see the exact name you mean.
Check whether your code contains a namespace which the right most part matches your static class name.
Given the a static Bar class, defined on namespace Foo, implementing a method Jump or a property, chances are you are receiving compiler error because there is also another namespace ending on Bar. Yep, fishi stuff ;-)
If that's so, it means your using a Using Bar; and a Bar.Jump() call, therefore one of the following solutions should fit your needs:
Fully qualify static class name with according namepace, which result on Foo.Bar.Jump() declaration. You will also need to remove Using Bar; statement
Rename namespace Bar by a diffente name.
In my case, the foollowing compiler error occurred on a EF (Entity Framework) repository project on an Database.SetInitializer() call:
Member 'Database.SetInitializer<MyDatabaseContext>(IDatabaseInitializer<MyDatabaseContext>)' cannot be accessed with an instance reference; qualify it with a type name instead MyProject.ORM
This error arouse when I added a MyProject.ORM.Database namespace, which sufix (Database), as you might noticed, matches Database.SetInitializer class name.
In this, since I have no control on EF's Database static class and I would also like to preserve my custom namespace, I decided fully qualify EF's Database static class with its namepace System.Data.Entity, which resulted on using the following command, which compilation succeed:
System.Data.Entity.Database.SetInitializer<MyDatabaseContext>(MyMigrationStrategy)
Hope it helps
YourClassName.YourStaticFieldName
For your static field would look like:
public class StaticExample
{
public static double Pi = 3.14;
}
From another class, you can access the staic field as follows:
class Program
{
static void Main(string[] args)
{
double radius = 6;
double areaOfCircle = 0;
areaOfCircle = StaticExample.Pi * radius * radius;
Console.WriteLine("Area = "+areaOfCircle);
Console.ReadKey();
}
}

Categories

Resources