如何調用受保護的構造函數?如何在c#中調用受保護的構造函數?
public class Foo{
public Foo(a lot of arguments){}
protected Foo(){}
}
var foo=???
這顯然有故障:
public class FooMock:Foo{}
var foo=new FooMock();
Assert(typeof(Foo), foo.GetType());
如何調用受保護的構造函數?如何在c#中調用受保護的構造函數?
public class Foo{
public Foo(a lot of arguments){}
protected Foo(){}
}
var foo=???
這顯然有故障:
public class FooMock:Foo{}
var foo=new FooMock();
Assert(typeof(Foo), foo.GetType());
你只能調用從一個子類,基本上是這樣。你FooMock
類就已經被調用受保護的構造,因爲它等同於:
public class FooMock : Foo
{
public FooMock() : base() // Call the protected base constructor
{
}
}
然而,你的斷言將失敗,因爲對象的類型提及的是foo
是FooMock
,不Foo
。
形式斷言foo is Foo
將通過通過。
您不能通過直接調用受保護的構造函數來構造只有Foo
的實例。它被保護而非公開的要點是確保它只被子類調用(或在Foo
本身的文本中)。
有可能你可以在完全信任的環境下用反射來調用它,但我希望你不要這樣做。
導致受保護的構造函數被調用的唯一方法是從該類派生並具有派生類委託給它或具有靜態方法創建它或一些其他內部方法。
編輯:什麼是Skeet說的!
您不能調用protected
方法 - 儘管您可以調用internal
之一(使用InternalsVisibleTo
屬性)。你需要以不同的方式公開它。
如果您需要顯式調用你的構造基類你的子類,你必須使用關鍵字base
呼叫參數的保護/私有構造:
Foo foo = (Foo)Activator.CreateInstance(typeof(Foo), true);
非電話帶參數的公共構造函數:
var foo = (Foo)typeof(Foo)
.GetConstructor(
BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance,
null,
new[] { typeof(double) },
null
)
.Invoke(new object[] { 1.0 });
class Foo
{
private Foo(double x){...}
}
Serj-Tm充分回答,但Activator可以也可以這樣做:
var foo = (Foo) Activator.CreateInstance(typeof(Foo),
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
null,
new object[] { 2.0 },
CultureInfo.InvariantCulture);
如果您想避免重複反射成本,可以使用表達式。 這是一個使用字符串值調用私有構造函數的示例。
private static Func<string, T> CreateInstanceFunc()
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var ctor = typeof(T).GetConstructors(flags).Single(
ctors =>
{
var parameters = ctors.GetParameters();
return parameters.Length == 1 && parameters[0].ParameterType == typeof(string);
});
var value = Expression.Parameter(typeof(string), "value");
var body = Expression.New(ctor, value);
var lambda = Expression.Lambda<Func<string, T>>(body, value);
return lambda.Compile();
}
通過將函數存儲在靜態字段中多次存儲編譯函數的代價。
private static readonly Lazy<Func<string, T>> CreateInstance = new Lazy<Func<string, T>>(CreateInstanceFunc);
現在,您可以創建
CreateInstance.Value("Hello")
的對象可能是這將有助於:
抽象父類:
public abstract class Animal
{
private string name;
public Animal(string name)
{
this.Name = name;
}
public Animal() { }
public string Name
{
get { return this.name; }
set { this.name = value; }
}
public virtual void talk()
{
Console.WriteLine("Hi,I am an animal");
}
}
類受保護的構造:
public class Lion : Animal
{
private string yahoo;
protected Lion(string name) : base(name)
{
this.Yahoo = "Yahoo!!!";
}
public string Yahoo
{
get
{
return yahoo;
}
set
{
yahoo = value;
}
}
public Lion() { }
}
類伽羅從獅子類派生:
public class Kiara : Lion
{
public Kiara(string name) : base(name)
{
}
public override void talk()
{
Console.WriteLine("HRRRR I'm a Kiara");
}
public Kiara() { }
}
類辛巴從獅子類派生:在主要功能
public class Simba : Lion
{
public Simba(string name) : base(name)
{
}
public override void talk()
{
Console.WriteLine("HRRRR I'm a {0} and this is my daughter:{1} {2}",
new Simba("Simba").Name,
new Kiara("Kiara").Name,
new Simba("Simba").Yahoo);
}
public Simba() { }
}
實現:
public static void Main(string[] args)
{
Animal lion = new Simba();
lion.Name = "Simba";
lion.talk();
Animal lion1 = new Kiara();
lion1.Name = "Kiara";
lion1.talk();
}
「不過我也希望你不這樣做「爲什麼不呢?我需要這個測試。也許這是有道理的,畢竟呢? – 2010-12-06 11:17:34
@Arnis L .:那時你只需要做一些測試就可以了,這跟測試根本沒有關係。現在是回顧並查看_why_這個構造函數是`protected`的好時機,因爲它意味着您尋求(並正在測試)的行爲顯式不受支持(因此不可測試)。 – David 2010-12-06 11:22:48
@Arnis:通常,如果您需要繞過具有反射的輔助功能模型,這表明您不應該嘗試訪問有問題的成員 - 或者您應該自行增加輔助功能。 – 2010-12-06 11:23:10