'ref'와 'out'이 다형성을 지원하지 않는 이유는 무엇입니까?
다음을 수행하십시오.
class A {}
class B : A {}
class C
{
C()
{
var b = new B();
Foo(b);
Foo2(ref b); // <= compile-time error:
// "The 'ref' argument doesn't match the parameter type"
}
void Foo(A a) {}
void Foo2(ref A a) {}
}
위의 컴파일 타임 오류가 발생하는 이유는 무엇입니까? 이것은 인수 ref
와 out
인수 모두에서 발생합니다 .
=============
업데이트 : 나는이 블로그 항목의 기초 로이 답변을 사용했습니다 :
ref 및 out 매개 변수가 유형 변형을 허용하지 않는 이유는 무엇입니까?
이 문제에 대한 자세한 설명은 블로그 페이지를 참조하십시오. 좋은 질문 감사합니다.
=============
의 당신이 수업을 가정하자 Animal
, Mammal
, Reptile
, Giraffe
, Turtle
와 Tiger
, 명백한 서브 클래스의 관계.
이제 방법이 있다고 가정하자 void M(ref Mammal m)
. M
읽고 쓸 수 있습니다 m
.
당신은 유형의 변수를 전달할 수
Animal
에M
?
아니요. 해당 변수는을 포함 할 수 Turtle
있지만 M
Mammals 만 포함한다고 가정합니다. A Turtle
는 Mammal
입니다.
결론 1 : ref
매개 변수를 "더 크게"만들 수 없습니다. (포유류보다 포유류가 많으므로 더 많은 것을 포함 할 수 있기 때문에 변수가 더 큽니다.)
당신은 유형의 변수를 전달할 수
Giraffe
에M
?
번호 M
에 기록 할 수있는 m
, 그리고 M
된 기록 할 수 있습니다 Tiger
로를 m
. 이제 Tiger
실제로 유형 인 변수 에을 넣었습니다 Giraffe
.
결론 2 : ref
매개 변수를 "더 작게"만들 수 없습니다.
이제 고려하십시오 N(out Mammal n)
.
당신은 유형의 변수를 전달할 수
Giraffe
에N
?
번호 N
에 쓸 수 n
및 N
를 작성 할 수 있습니다 Tiger
.
결론 3 : out
매개 변수를 더 작게 만들 수 없습니다.
당신은 유형의 변수를 전달할 수
Animal
에N
?
흠.
왜 안돼? N
에서 읽을 수없고 n
쓰기 만 할 수 있습니다. Tiger
타입의 변수에 a 를 쓰면 Animal
모든 것이 설정됩니다.
잘못된. 규칙은 " N
쓸 수 없습니다" 는 아닙니다 n
.
규칙은 다음과 같습니다.
1) 반품 전에 정상적으로 N
써야 합니다. (경우 가 발생, 모든 베팅은 꺼져 있습니다.)n
N
N
2)에서 N
무언가를 n
읽기 전에 무언가를 써야합니다 n
.
이를 통해 다음과 같은 일련의 이벤트가 가능합니다.
- Declare a field
x
of typeAnimal
. - Pass
x
as anout
parameter toN
. N
writes aTiger
inton
, which is an alias forx
.- On another thread, someone writes a
Turtle
intox
. N
attempts to read the contents ofn
, and discovers aTurtle
in what it thinks is a variable of typeMammal
.
Clearly we want to make that illegal.
Conclusion 4: out
parameters cannot be made "larger".
Final conclusion: Neither ref
nor out
parameters may vary their types. To do otherwise is to break verifiable type safety.
If these issues in basic type theory interest you, consider reading my series on how covariance and contravariance work in C# 4.0.
Because in both cases you must be able to assign value to ref/out parameter.
If you try to pass b into Foo2 method as reference, and in Foo2 you try to assing a = new A(), this would be invalid.
Same reason you can't write:
B b = new A();
You're struggling with the classic OOP problem of covariance (and contravariance), see wikipedia: much as this fact may defy intuitive expectations, it's mathematically impossible to allow substitution of derived classes in lieu of base ones for mutable (assignable) arguments (and also containers whose items are assignable, for just the same reason) while still respecting Liskov's principle. Why that is so is sketched in the existing answers, and explored more deeply in these wiki articles and links therefrom.
OOP languages that appear to do so while remaining traditionally statically typesafe are "cheating" (inserting hidden dynamic type checks, or requiring compile-time examination of ALL sources to check); the fundamental choice is: either give up on this covariance and accept practitioners' puzzlement (as C# does here), or move to a dynamic typing approach (as the very first OOP language, Smalltalk, did), or move to immutable (single-assignment) data, like functional languages do (under immutability, you can support covariance, and also avoid other related puzzles such as the fact that you cannot have Square subclass Rectangle in a mutable-data world).
Consider:
class C : A {}
class B : A {}
void Foo2(ref A a) { a = new C(); }
B b = null;
Foo2(ref b);
It would violate type-safety
While the other responses have succinctly explained the reasoning behind this behavior, I think it's worth mentioning that if you really need to do something of this nature you can accomplish similar functionality by making Foo2 into a generic method, as such:
class A {}
class B : A {}
class C
{
C()
{
var b = new B();
Foo(b);
Foo2(ref b); // <= no compile error!
}
void Foo(A a) {}
void Foo2<AType> (ref AType a) where AType: A {}
}
Because giving Foo2
a ref B
would result in a malformed object because Foo2
only knows how to fill A
part of B
.
Isn't that the compiler telling you it would like you to explicitly cast the object so that it can be sure you know what your intentions are?
Foo2(ref (A)b)
Makes sense from a safety perspective, but I would have preferred it if the compiler gave a warning instead of an error, since there are legitimate uses of polymoprhic objects passed by reference. e.g.
class Derp : interfaceX
{
int somevalue=0; //specified that this class contains somevalue by interfaceX
public Derp(int val)
{
somevalue = val;
}
}
void Foo(ref object obj){
int result = (interfaceX)obj.somevalue;
//do stuff to result variable... in my case data access
obj = Activator.CreateInstance(obj.GetType(), result);
}
main()
{
Derp x = new Derp();
Foo(ref Derp);
}
This won't compile, but would it work?
If you use practical examples for your types, you'll see it:
SqlConnection connection = new SqlConnection();
Foo(ref connection);
And now you have your function that takes the ancestor (i.e. Object
):
void Foo2(ref Object connection) { }
What can possibly be wrong with that?
void Foo2(ref Object connection)
{
connection = new Bitmap();
}
You just managed to assign a Bitmap
to your SqlConnection
.
That's no good.
Try again with others:
SqlConnection conn = new SqlConnection();
Foo2(ref conn);
void Foo2(ref DbConnection connection)
{
conn = new OracleConnection();
}
You stuffed an OracleConnection
over-top of your SqlConnection
.
In my case my function accepted an object and I couldn't send in anything so I simply did
object bla = myVar;
Foo(ref bla);
And that works
My Foo is in VB.NET and it checks for type inside and does a lot of logic
I apologize if my answer is duplicate but others were too long
참고URL : https://stackoverflow.com/questions/1207144/why-doesnt-ref-and-out-support-polymorphism
'programing tip' 카테고리의 다른 글
git을 Xcode와 통합 할 수 있습니까? (0) | 2020.07.11 |
---|---|
iOS / macOS에서 프로그래밍 방식으로 내 IP 주소를 얻는 방법은 무엇입니까? (0) | 2020.07.11 |
git update-index --skip-worktree 실행 취소 (0) | 2020.07.10 |
iPhone에서 NSString에 대한 AES 암호화 (0) | 2020.07.10 |
C #에서 'T : class'는 무엇을 의미합니까? (0) | 2020.07.10 |