好的,让我说我有一个像这样的结构A:
Struct A{
private String _SomeText;
private int _SomeValue;
public A(String someText, int SomeValue) { /*.. set the initial values..*/ }
public String SomeText{ get { return _SomeText; } }
public int SomeValue{ get { return _SomeValue; } }
}
现在我想要做的是返回结构A作为类ABC中的方法的结果,如:
Class ABC{
public A getStructA(){
//creation of Struct A
return a;
}
}
我不希望任何程序员使用我的库(具有Struct A和Class ABC以及更多东西)来创建Struct A的实例。
我希望创建它的唯一方法是从getStructA()方法返回。然后可以通过适当的getter访问这些值。
那么有没有办法设置这样的限制?那么一个结构不能在某个类之外实例化?使用C#,。Net4.0。
感谢您的帮助。
---编辑:----
要添加一些有关我为什么要实现此目标的详细信息:
所以我可以创建一个公共结构,程序员可以根据需要实例化它,这对他们来说没用,因为没有方法可以接受它作为参数。或者我可以以这样的方式构造库:这个结构(或者如果它使事情变得更容易将它改为类)只能作为方法的返回来获得。
答案 0 :(得分:10)
如果“受限制”类型是结构,那么不,没有办法做到这一点。结构必须至少与工厂方法一样公开,如果结构是公共的,那么它可以使用其默认构造函数构造。但是,您可以这样做:
public struct A
{
private string s;
private int i;
internal bool valid;
internal A(string s, int i)
{
this.s = s;
this.i = i;
this.valid = true;
}
...
现在您可以让您的库代码检查“有效”标志。 A的实例只能通过(1)通过库内部可以调用内部构造函数的方法或(2)通过默认构造函数来实现。您可以使用有效标志区分它们。
许多人建议使用界面,但这有点无意义;使用结构的全部意义在于获取值类型语义,然后将其装入接口。你最好还是让它成为一个班级。如果它将成为一个类,那么肯定可以制造工厂方法;只是让班上的所有人都在内部。
当然,我希望不言而喻,不应该使用这些设备来实现能够抵抗完全信任用户攻击的代码。请记住,此系统用于保护好用户免受错误代码的影响,而不是来自坏用户的良好代码。没有任何东西可以阻止完全受信任的用户代码通过反射调用它们在库中所需的任何私有方法,或者就此而言,使用不安全的代码更改结构中的位。
答案 1 :(得分:0)
创建一个公共接口,并使该类对调用它的类是私有的。
public ISpecialReturnType
{
String SomeText{ get; }
int SomeValue{ get; }
}
class ABC{
public ISpecialReturnType getStructA(){
A a = //Get a value for a;
return a;
}
private struct A : ISpecialReturnType
{
private String _SomeText;
private int _SomeValue;
public A(String someText, int SomeValue) { /*.. set the initial values..*/ }
public String SomeText{ get { return _SomeText; } }
public int SomeValue{ get { return _SomeValue; } }
}
}
答案 2 :(得分:0)
如果要确保您的方法不接受除您的类型在内部生成的类型之外的任何类型的实例,则应使用仅具有internal
或private
构造函数的类。如果你这样做,你可以确定你正在获得你自己生成的实例。
修改的 根据修订,我不认为所要求的限制类型是必要的或特别有用。这听起来像是根本上希望将一堆值粘在一起并将它们存储到调用者所持有的一组固定变量中。如果您将结构声明为:
public struct QueryResult {
public ExecutionDuration as Timespan;
public CompletionTime as DateTime;
public ReturnedMessage as String;
}
然后声明:
QueryResult foo;
将有效地创建三个变量,名为foo.ExecutionDuration
,foo.CompletionTime
和foo.ReturnedMessage
。声明:
foo = queryPerformer.performQuery(...);
将根据函数的结果设置这三个变量的值 - 基本上等同于:
{
var temp = queryPerformer.performQuery(...);
foo.ExecutionDuration = temp.ExecutionDuration
foo.CompletionTime = temp.CompletionTime;
foo.ReturnedMessage = temp.ReturnedMessage;
}
没有什么能阻止用户代码用这三个变量做任何想做的事情,但那又怎样呢?如果用户代码决定说出foo.ReturnedMessage = "George";
的任何理由,那么foo.ReturnedMessage
将等于George
。如果代码说的话,情况确实没有什么不同:
int functionResult = doSomething();
然后说functionResult = 43;
。与任何其他变量一样,functionResult
的行为是保留写入它的最后一件事。如果写入的最后一件事是最后一次调用doSomething()
的结果,那就是它将保留的内容。如果最后写的东西是别的东西,那么它将拥有别的东西。
请注意,与类字段或结构属性不同,结构字段只能通过写入 来更改,或者通过使用结构赋值语句将所有字段写入一个 struct实例,其中包含另一个的相应字段中的值。从消费者的角度来看,只读struct属性没有这样的保证。结构可能碰巧实现一个属性来表现那种方式,但是如果不检查属性的代码,就无法知道它返回的值是否会受到某个可变对象的影响。