Насколько я знаю Вас, банка не может передать параметры статическому конструктору в C#. Однако у меня действительно есть 2 параметра, я должен передать и присвоить их статическим полям, прежде чем я создам экземпляр класса. Как я иду об этом?
Это может быть вызов ... фабричного метода!
class Foo
{
private int bar;
private static Foo _foo;
private Foo() {}
static Foo Create(int initialBar)
{
_foo = new Foo();
_foo.bar = initialBar;
return _foo;
}
private int quux;
public void Fn1() {}
}
Вы можете поставить проверку, что «полоса» уже инициализирована (или нет) соответствующим образом.
Вы не можете передавать параметры статическому конструктору, но вы можете передавать параметры самому классу - через параметры общего типа.
Немного безумная идея, однако, я все равно ее выскажу.
Сделать класс generic (с TypeParam, который будет предоставлять тип параметра) и наложить на него generic-ограничения (подробности в примере кода), затем вывести новый тип параметра, который содержит виртуалки, которые можно использовать для чтения того, какими должны быть значения параметров.
//base parameter type - provides the 'anchor' for our generic constraint later,
//as well as a nice, strong-typed access to our param values.
public class StaticParameterBase
{
public abstract string ParameterString{ get; }
public abstract MyComplexType ParameterComplex { get; }
}
//note the use of the new() generic constraint so we know we can confidently create
//an instance of the type.
public class MyType<TParameter> where TParameter:StaticParameterBase, new()
{
//local copies of parameter values. Could also simply cache an instance of
//TParameter and wrap around that.
private static string ParameterString { get; set; }
private static MyComplexType ParameterComplex { get; set; }
static MyType()
{
var myParams = new TParameter();
ParameterString = myParams.ParameterString;
ParameterComplex = myParams.ParameterComplex;
}
}
//e.g, a parameter type could be like this:
public class MyCustomParameterType : StaticParameterBase
{
public override string ParameterString { get { return "Hello crazy world!"; } }
public override MyComplexType { get {
//or wherever this object would actually be obtained from.
return new MyComplexType() { /*initializers etc */ };
}
}
}
//you can also now derive from MyType<>, specialising for your desired parameter type
//so you can hide the generic bit in the future (there will be limits to this one's
//usefulness - especially if new constructors are added to MyType<>, as they will
//have to be mirrored on this type as well).
public class MyType2 : MyType<MyCustomParameterType> { }
//then you'd use the type like this:
public static void main()
{
var instance = new MyType<MyCustomParameterType>();
//or this:
var instance2 = new MyType2();
}
Я рассматривал решение, при котором пользовательские атрибуты типа применяются к параметру типа, однако этот способ легко может быть лучше. Однако теперь вы будете использовать свой класс всегда с общим типом параметра (если только вы не сможете использовать трюк deriving+specialisation) - возможно, слишком неуклюже для вашего вкуса.
Я бы также предпочел этот вариант другим представленным здесь решениям, поскольку он не требует создания обходных путей для статической инициализации - вы все еще можете использовать гарантию .Net на однократную инициализацию.
Слово предупреждения - следует ли вам пересмотреть свою структуру?
Все это сказано - помните, однако, что поскольку вы можете параметризовать статику только один раз (или, в данном случае, каждый уникально параметризованный статический дженерик) - я бы спросил себя, почему бы просто не вытащить код, который получает параметры для передачи статике, и не поместить его в статический конструктор в первую очередь? Тогда вам не придется прибегать к таким странным шаблонам, как этот!
Полагаю, вы имеете в виду статические члены класса? В этом случае вы можете сделать следующее:
public class MyClass
{
public static int MyInt = 12;
public static MyOtherClass MyOther = new MyOtherClass();
}
Эти статические члены гарантированно будут созданы до того, как будет создан какой-либо класс.
Если вам нужна сложная логика, сделайте это в статическом конструкторе:
public class MyClass
{
public static int MyInt;
public static MyOtherClass MyOther;
static MyClass()
{
MyInt = 12;
MyOther = new MyOtherClass();
}
}
Edit
На основании вашего редактирования, я бы сказал, просто назначьте значения тем, что они должны быть, прежде чем вы создадите экземпляр класса, например :
public class MyClass
{
public static int MyInt;
public static MyOtherClass MyOther;
}
// elsewhere in code, before you instantiate MyClass:
MyClass.MyInt = 12;
MyClass.MyOther = new MyOtherClass();
MyClass myClass = new MyClass();
Тем не менее, этот метод не дает вам гарантии, что MyInt и MyOther установлены до создания экземпляра MyClass. Это будет работать, но перед созданием экземпляра MyClass потребуется дисциплина.
Один альтернативный шаблон, которому вы можете следовать, выглядит следующим образом:
public class MyClass
{
private static int MyInt;
private static MyOtherClass MyOther;
private static bool IsStaticInitialized = false;
public static InitializeStatic(int myInt, MyOtherClass other)
{
MyInt = myInt;
MyOther = other;
IsStaticInitialized = true;
}
public MyClass()
{
if(!IsStaticInitialized)
{
throw new InvalidOperationException("Static Not Initialized");
}
// other constructor logic here.
}
}
// elsewhere in your code:
MyClass.InitializeStatic(12, new MyOtherClass());
MyClass myClass = new MyClass();
// alternatiavely:
MyClass myClass = new MyClass(); // runtime exception.