일반적으로 C # 또는 .NET Framework의 가장 큰 디자인 결함은 무엇입니까?
예 : nullable이 아닌 문자열 유형이 없으며 IDataReader에서 값을 가져올 때 DBNull을 확인해야합니다.
일반적으로 C # 또는 .NET Framework의 가장 큰 디자인 결함은 무엇입니까?
예 : nullable이 아닌 문자열 유형이 없으며 IDataReader에서 값을 가져올 때 DBNull을 확인해야합니다.
답변:
나는 이 게시물에 단호하게 동의합니다 (ToString이 부족한 사람들을 위해 클래스에 대한 사용자 정의 형식을 제공하는 디버거 속성이 있습니다).
위의 목록 위에 다음과 같은 합리적인 요청을 추가합니다.
T : new(string)또는 어디T : new(string, int)var e = new Foo(); e { Bar = baz };Either<T>" 와 같은 효율적인 폐쇄 형 대수 유형 은 그렇지 않습니다. 따라서 폐쇄 형 대수 유형을 선언하고 철저한 패턴 일치를 적용하는 방법을 좋아합니다 (기본적으로 방문자 패턴에 대한 일급 지원이지만 훨씬 더 효율적입니다. 따라서 열거 형을 취하고 철저한 패턴 일치 지원으로 확장하고 유효하지 않은 경우를 허용하지 마십시오.System.IO같은 클래스 Stream가 다소 잘못 설계 되었다는 다른 게시물에 동의합니다 . 일부 구현이 필요한 인터페이스 NotSupportedException는 잘못된 디자인입니다.IList현재보다 훨씬 간단해야합니다. 사실, 이것은 다음과 같은 많은 구체적인 컬렉션 인터페이스에 해당 될 수 있습니다 ICollection.INotifyPropertyChanged필드 이름을 문자열로 사용하는 인터페이스의 필드 및 멤버 이름을 안전하게 반영하는 방법을 제공 합니다. MemberExpression, 즉 람다를 사용하는 확장 메서드를 사용하여이를 수행 할 수 있습니다 . () => Foo하지만 그다지 효율적이지 않습니다.
nameof()은 단일 멤버 이름에 대한 연산자를 추가 했지만 제네릭에서는 작동하지 않습니다 ( nameof(T) == "T"실제 형식 인수 이름 대신 수행해야 함 typeof(T).Name))- "경로"문자열을 가져올 수도 없습니다. , 예 : nameof(this.ComplexProperty.Value) == "Value"가능한 응용 프로그램 제한.IArithmetic. 다른 유용한 공유 운영자 인터페이스도 가능합니다.readonly키워드가 있고 C # 6.0은 읽기 전용 자동 속성을 추가했지만 변경 불가능한 유형 및 값에 대한 실제 언어 지원만큼 엄격하지는 않습니다.지금은 충분하다고 생각합니다. 이것들은 지난주에 내가 만난 모든 자극입니다. 정말로 마음을 쏟으면 몇 시간 동안 계속할 수있을 것입니다. C # 4.0은 이미 명명 된, 선택적 및 기본 인수를 추가하고 있습니다.
이제 한 가지 비합리적인 요청 :
제발요? :-)
List<T>백만 Ts를 얻었습니다 . 스냅 샷을 효율적으로 촬영할 것을 어떻게 제안합니까? # 21 : readonly키워드를 사용하십시오 .... 여기에 좋은 제안이 있지만 대부분 디자인 결함이 아닌 제안 일뿐입니다.
Reset()메서드 IEnumerator<T>가 실수였습니다 (반복자 블록의 경우 언어 사양 에서 예외가 발생하도록 요구 합니다)IEnumerable<out T>및 Func<in T, out TResult>과 같지만 구체적인 형식 (예 :) 은 List<T>아님).ApplicationException 오히려 호의적으로 떨어졌습니다-그게 실수였습니까?Contains, then Add) 을 동기화해야 하므로 개별 작업을 동기화하는 컬렉션은 그다지 유용하지 않습니다.
System.Collections.ConcurrentTryAddGetOrAddTryRemoveusing/ lock패턴을 더 많이 사용할 수 있습니다 .-아마도 재사용 가능한 (확장 가능한?) 구문을 공유 할 수 있습니다. 을 (를) 반환 IDisposable하고 사용하여 시뮬레이션 할 수 using있지만 더 명확 할 수 있습니다.Foo(SqlConnection! connection)(null-check / 주입) 와 같은 구문은 throw좋을 것입니다 (대비 int?등)
dynamic은을 사용 하여이 문제를 약간 해결 하거나 다음 과 같이 활성화 할 수 있습니다.foreach, 즉 anon-methods / lambda가 반복 당 하나가 아닌 단일 변수를 캡처 함을 의미합니다 (스레딩 / 비동기 등으로 고통 스러움).
ApplicationException실수 라고 말했습니다 . 그들이 바라는 것처럼 유용하지 않습니다. 그들은 또한 그랬어 System.Exception야한다고 말했다 abstract.
TextWriter는 StreamWriter 의 기본 클래스입니다. 뭐?
그것은 항상 나를 극도로 혼란스럽게 만듭니다.
작은 C # pet peev-생성자는 C ++ / Java 구문을 사용하여 생성자가 클래스와 동일한 이름이되도록합니다.
New()아니면 ctor()훨씬 더 좋았을 것입니다.
물론 coderush와 같은 도구를 사용하면 클래스 이름을 바꿀 때이 문제를 덜 수 있지만 가독성 관점에서 New ()는 매우 명확합니다.
class Foo { new(int j) {i = j} int i; }
New대문자 키워드는 관례에 위배 되지 않음 ), 디자인 결함이라고 부르는 것을 주저합니다. 그들은 기존의 C ++ / Java 개발자를 끌어 들이고 싶었고, 어리석은 오래된 구문 규칙을 많이 빌려서 목표를 달성하는 데 도움이되었을 것입니다.
당신이 할 수 없다는 것을 이해하지 못합니다
여기서 T : new (U)
따라서 제네릭 유형 T에 기본이 아닌 생성자가 있다고 선언합니다.
편집하다:
나는 이것을하고 싶다 :
public class A
{
public A(string text)
{
}
}
public class Gen<T> where T : new(string text)
{
}
나는 이것을 처음 언급 한 것이 정말 놀랍습니다.
ADO.NET 형식화 된 데이터 집합은 nullable 형식의 속성으로 nullable 열을 노출하지 않습니다. 다음과 같이 작성할 수 있어야합니다.
int? i = myRec.Field;
myRec.Field = null;
대신 다음과 같이 작성해야합니다. 이것은 어리석은 일입니다.
int? i = (int?)myRec.IsFieldNull() ? (int?)null : myRec.Field;
myRec.SetFieldNull();
이것은 .NET 2.0에서 성가신 일이었고 멋진 깔끔한 LINQ 쿼리에서 위와 같은 jiggery-pokery를 사용해야하므로 훨씬 더 성가신 일입니다.
또한 생성 된 Add<TableName>Row메서드가 nullable 형식의 개념과 비슷하게 무의미 하다는 것도 성가신 일입니다 . 생성 된 TableAdapter메서드가 아니기 때문에 더욱 그렇습니다 .
.NET에는 개발팀이 "좋아요, 우리는 충분히 가까웠습니다. 배송 해주세요!"라고 말한 것 같은 느낌이 들지 않습니다. 그러나 이것은 확실합니다.
DBNull.Value, null그 자체가 NULL을 표현하기에 완벽하게 적절 했을 때 . 다행히 LINQ-to-SQL은 NULL에 대해 null을 사용합니다.
편집
5. 또 다른 성가심은 System.Reflection.BindingFlags가 사용하는 방법에 따라 다른 용도로 사용된다는 것입니다. 예를 들어 FindFields에서 CreateInstance 또는 SetField는 무엇을 의미합니까? 이것은 그들이 혼란스러운이 열거 뒤에있는 의미를 오버로드 한 경우입니다.
디자인상의 결함이라고 말할 수 있을지는 모르겠지만, VB에서와 같은 방식으로 람다 식을 추론 할 수 있다면 정말 좋을 것입니다.
VB :
Dim a = Function(x) x * (x - 1)
씨#
이렇게 할 수 있다면 좋을 것입니다.
var a = x => x * (x - 1);
이렇게하는 대신 :
Func<int, int> a = x => x * (x - 1);
그다지 길지 않다는 것을 알고 있지만 Code Golf에서는 모든 캐릭터가 망할 수 있습니다! 그들은 이러한 프로그래밍 언어를 설계 할 때 그것을 고려하지 않습니까? :)
(int x) => x * (x -1);은 의미 Func<int, int>하거나 의미 할 수 있습니다Expression<Func<int, int>>
+대해 정의 되지 않았기 때문에 C #은 할 수 없습니다 object.
은 System.Object의 클래스 :
Equals 및 GetHashCode-모든 클래스가 비교 가능하거나 해시 가능한 것은 아니므로 인터페이스로 이동해야합니다. IEquatable 또는 IComparable (또는 유사)이 떠 오릅니다.
ToString-모든 클래스를 문자열로 변환 할 수있는 것은 아니므로 인터페이스로 이동해야합니다. IFormattable (또는 유사)이 떠 오릅니다.
Generics는 처음부터 있어야합니다.
EqualityComparer<T>.Default올바르게 업데이트하는 것입니다. 그런 다음 var dict = new Dictionary<object, string>(EqualityComparer<object>.Default)및 둘 다 var dict = new Dictionary<object, string>()참조 비교 / 동등을 사용합니다.
EqualityComparer<T>.Default합니다. 조회 할 때마다 확인할 필요가 없습니다. 비교자는 Dictionary인스턴스에 대한 속성 이며 각각 Dictionary이 사용중인 것을 알고 있습니다.
저를 짜증나게하는 것 중 하나는 Predicate<T> != Func<T, bool>역설입니다. 둘 다 유형의 대리자 T -> bool이지만 할당과 호환되지 않습니다.
어떤 사람들 (ISV)은 dotNet 런타임이 필요하지 않은 네이티브 실행 파일을 만들기 위해 빌드 타임에 머신 코드로 컴파일하고 링크 할 수 있기를 바랍니다.
우리는 권리 에 대해 너무 많이 알고 있습니다. OO 기술 있습니다. 디커플링, 계약에 의한 프로그래밍, 부적절한 상속 방지, 적절한 예외 사용, 개방 / 폐쇄 주체, Liskov 대체 가능성 등. 아직 .Net 프레임 워크는 모범 사례를 사용하지 않습니다.
나에게 .Net 디자인의 가장 큰 결함은 거인의 어깨에 서 있지 않습니다. 프레임 워크를 사용하는 수많은 프로그래머에게 이상적이지 않은 프로그래밍 패러다임을 홍보 합니다.
MS가 이에주의를 기울 였다면 소프트웨어 엔지니어링 세계는 이번 10 년 동안 품질, 안정성 및 확장 성 측면에서 큰 도약을 할 수 있었지만 아쉽게도 퇴보하고있는 것 같습니다.
C # switch 문이 마음에 들지 않습니다.
나는 이것과 같은 것을 원한다
switch (a) {
1 : do_something;
2 : do_something_else;
3,4 : do_something_different;
else : do_something_weird;
}
따라서 더 이상 끊기지 않고 (잊기 쉬움) 다른 값을 쉼표로 구분할 수 있습니다.
switchC의 의도적으로 불구가 된 버전을 모방하는 모든 언어에서 근본적으로 깨졌습니다 (속도 최적화!). VB는 훨씬 더 나은 요금이지만 패턴 매칭을 사용하는 언어 (Haskell, F #…)보다 여전히 광년 뒤쳐져 있습니다.
리스너를 명시 적으로 확인해야하는 C #의 이벤트. 이벤트의 핵심이 아니 었나요? 아무것도 없어도?
중첩 / 재귀 반복기 의 끔찍한 (그리고 대부분의 사람들에게는 보이지 않는) O (N ^ 2) 동작 .
나는 그들이 그것에 대해 알고 있고, 그것을 고치는 방법을 알고 있다는 사실에 상당히 당혹스러워 하지만, 포함할만한 충분한 우선 순위를 가지고 있지 않다고 생각합니다.
나는 항상 트리와 같은 구조로 작업하고, 이런 식으로 고비용의 작업을 실수로 도입 할 때 똑똑한 사람들의 코드를 수정해야합니다.
"yield foreach"의 장점은 더 간단하고 쉬운 구문이 정확하고 성능이 좋은 코드를 장려 한다는 것입니다. 이것이 플랫폼의 장기적인 성공을 위해 새로운 기능을 추가하기 전에 열망해야 할 "성공의 구덩이" 입니다.
일부 클래스는 인터페이스를 구현하지만 해당 인터페이스의 많은 메서드를 구현하지 않습니다. 예를 들어 Array는 IList를 구현하지만 9 개 중 4 개 메서드는 NotSupportedException을 throw합니다 . .aspx
인터페이스의 정적 멤버 및 중첩 유형.
인터페이스 부재는 인터페이스에 특정한 타입의 파라미터 (가질 때 특히 유용 예 을 enum). 인터페이스 유형에 열거 유형을 중첩하는 것이 좋습니다.
이벤트의 매우 위험한 기본 특성. 이벤트를 호출 할 수 있고 구독자가 제거되어 일관성이없는 상태에 있다는 사실은 끔찍합니다. 주제에 대한 자세한 내용은 Jon Skeet 및 Eric Lippert의 우수한 기사를 참조하십시오.
null 어디에나.
const 아무데도.
API는 일관성이 없습니다. 예를 들어 배열을 변경하면 반환 void되지만에 추가 StringBuffer하면 동일한 mutable 이 반환 StringBuffer됩니다.
컬렉션 인터페이스는 불변 데이터 구조와 호환되지 않습니다. 예를 들어 Addin System.Collections.Generic.IList<_>은 결과를 반환 할 수 없습니다.
구조적인 입력하면 쓸 수 있도록 System.Windows.Media.Effects.SamplingMode.Bilinear대신의 Bilinear.
IEnumerator불변이어야 할 때 클래스에 의해 구현 된 가변 인터페이스 struct.
평등과 비교 엉망입니다 : 당신이있어 System.IComparable하고 Equals그러나 당신은 또한있어 System.IComparable<_>, System.IEquatable, System.Collections.IComparer, System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.Collections.Generic.IComparer와 System.Collections.Generic.IEqualityComparer.
튜플은 구조체 여야하지만 구조체는 꼬리 호출 제거를 불필요하게 금지하므로 가장 일반적이고 기본적인 데이터 유형 중 하나가 불필요하게 할당되고 확장 가능한 병렬 처리가 파괴됩니다.
IEnumerator어떻게 사용 합니까?
열거 형으로 0 달빛
enum의 특성 : http://blogs.msdn.com/abhinaba/archive/2007/01/09/more-peculiarites-of-enum.aspx
이 좋은 예에서 설명한대로 : http://plus.kaist.ac.kr/~shoh/postgresql/Npgsql/apidocs/Npgsql.NpgsqlParameterCollection.Add_overload_3.html
내 제안, "@"기호를 잘 사용하십시오.
대신에:
if ((myVar & MyEnumName.ColorRed)! = 0)
이것을 사용하십시오 :
if ((myVar & MyEnumName.ColorRed)! = @ 0)
이미 다른 사람들이 만든 좋은 점의 긴 목록에 추가하려면 :
DateTime.Now == DateTime.Now 대부분의 경우이지만 모든 경우는 아닙니다.
String불변 인 것은 구성과 조작을위한 많은 옵션을 가지고 있지만 StringBuilder(변할 수있는) 그렇지 않습니다.
Monitor.Enter 과 Monitor.Exit 해야하고 인스턴스 메서드, 그래서 대신 잠금에 대해 특정 오브젝트를 newing, 그럴 수있어 새로 만들기 Monitor가에 및 잠금.
소멸자는 소멸자로 명명되어서는 안됩니다. ECMA 사양에서는이를 종료 자라고 부르며 C ++ 군중에게는 훨씬 덜 혼란 스럽지만 언어 사양에서는 여전히이를 소멸 자라고합니다.
DateTime.Now하나는 나머지 세계의 가장 확실한 경쟁 조건, 그러나 +1
우리가 속성을 사용하는 방식은 때때로 나를 짜증나게합니다. 나는 그것들을 Java의 getFoo () 및 setFoo () 메소드와 동등하다고 생각하고 싶습니다. 하지만 그렇지 않습니다.
는 IF 속성 사용 지침의 직렬화가 작동 할 수 있도록 속성 수 있어야 상태, 임의의 순서로 설정해야합니다 그들은있는 거 세터시의 검증을위한 쓸모. 개체가 잘못된 상태가되는 것을 방지하려는 배경에서 온 경우 속성은 솔루션이 아닙니다. 때때로 나는 그들이 공공 회원들보다 얼마나 더 나은지 보지 못합니다. 우리는 부동산에서 해야 할 일의 종류가 너무 제한 되어 있기 때문입니다.
이를 위해 저는 항상 속성 구문을 어떻게 든 확장 할 수 있기를 바랐습니다 (대부분 여기에서 큰 소리로 생각하고 있습니다. 저는 이런 식으로 할 수 있기를 바랍니다). 다음과 같이 상상해보십시오.
private string password;
public string Password
{
// Called when being set by a deserializer or a persistence
// framework
deserialize
{
// I could put some backward-compat hacks in here. Like
// weak passwords are grandfathered in without blowing up
this.password = value;
}
get
{
if (Thread.CurrentPrincipal.IsInRole("Administrator"))
{
return this.password;
}
else
{
throw new PermissionException();
}
}
set
{
if (MeetsPasswordRequirements(value))
{
throw new BlahException();
}
this.password = value;
}
serialize
{
return this.password;
}
}
그것이 유용한 지 또는 액세스하는 것이 어떻게 생겼는지 잘 모르겠습니다. 하지만 속성으로 더 많은 작업을 수행하고 실제로 get 및 set 메서드처럼 처리 할 수 있기를 바랍니다.
확장 방법은 좋지만 믹스 인의 주제에 대해 실제 믹스 인으로 더 깨끗하게 해결할 수있는 문제를 해결하는 추악한 방법입니다 (내가 말하는 내용을 보려면 루비를보세요). 그것들을 언어에 추가하는 정말 좋은 방법은 제네릭을 상속에 사용할 수있게하는 것이었을 것입니다. 이를 통해 기존 클래스를 멋진 객체 지향 방식으로 확장 할 수 있습니다.
public class MyMixin<T> : T
{
// etc...
}
다음과 같이 문자열을 확장하는 데 사용할 수 있습니다.
var newMixin = new MyMixin<string>();
예를 들어 언어 내부에서 AOP와 유사한 기능을 허용하는 래핑과 같이 메서드를 재정의 할 수 있기 때문에 확장 메서드보다 훨씬 강력합니다.
폭언 죄송합니다 :-)
Microsoft는 프레임 워크의 명백한 버그를 수정하지 않으며 최종 사용자가 수정할 수 있도록 후크를 제공하지 않습니다.
또한 런타임에 .NET 실행 파일을 바이너리 패치 할 수있는 방법이 없으며 네이티브 라이브러리를 바이너리 패치하지 않고 (로드 호출을 가로 채기 위해) .NET 프레임 워크 라이브러리의 비공개 버전을 지정할 방법이 없으며 ILDASM은 재배포 할 수 없으므로 자동화 할 수 없습니다. 어쨌든 패치.
null 변수에 대한 확장 메서드를 호출 할 수 있어야합니다.
개체 a = null; a.MyExtMethod (); // 이것은 호출 가능합니다. MyExtMethod를 정의한 어딘가에 가정합니다.
편리 할 수는 있지만 null 참조 예외 항목에서는 모호합니다.
하나의 명명 '결함'. System.configuration.dll에서 "configuration"의 'C'는 대문자 여야합니다.
예외 처리. 예외는 Java에서와 같이 강제로 포착되거나 throw되어야하며 컴파일러는 컴파일시이를 확인해야합니다. 사용자는 대상 호출 내의 예외 정보에 대한 주석에 의존해서는 안됩니다.
프레임 워크 V1의 SqlCommand에있는 .Parameters.Add () 메서드는 끔찍하게 설계되었습니다. 값 (int)이 0 인 매개 변수를 전달하면 오버로드 중 하나가 기본적으로 작동하지 않습니다. SqlCommand 클래스의 .Parameters.AddWithValue () 메서드
ICollection<T>및의 하위 집합이 없습니다 IList<T>. 최소한 공변 읽기 전용 컬렉션 인터페이스 IListSource<out T>(열거 자, 인덱서 및 Count 포함)는 매우 유용했습니다.Transform(Sequence<T>, Func<T,T>)에서 함수가 동일한 값을 반환하는지 다른 값을 반환하는지 신속하게 결정하는 데 필요한 함수를 작성했습니다 . 함수가 인수의 대부분 / 전체를 수정하지 않으면 출력 시퀀스가 입력 시퀀스의 일부 / 전체 메모리를 공유 할 수 있습니다. 값 유형 T를 비트 단위로 비교할 수없는 경우 훨씬 더 느린 비교를 사용해야하므로 성능이 크게 저하됩니다.List<T>가상 IListSource<U>(T : U) 으로 캐스팅 할 수 있습니다. 적어도이 있습니다 세 가지 다른 라이브러리 이 기능을 공급하는 (독립적으로 작성) (물론, 성능 단점으로는 - 완벽한 해결 방법은 할 수만 있으면 그것을 .NET의 결함으로 호출하는 공정을하지 않을 것이다).WeakReference<T>(쉽게 직접 작성할 수 있지만 내부적으로 캐스트를 사용합니다.)Predicate<T>vs Func<T,bool>) 에 대해 성가신 일이었습니다 . .NET에서는 독립 DLL의 클래스가 동일한 인터페이스를 구현하는 것만으로는 충분하지 않기 때문에 컴포넌트 간의 결합을 완화하기 위해 인터페이스와 델리게이트에 대한 구조적 유형 지정 을 원합니다. 인터페이스를 정의하는 DLL입니다.DBNull.Valuenull동일한 목적을 똑같이 잘 수행했을 지라도 존재 합니다.variable = variable ?? value. 실제로 C #에는 불필요하게 대칭이 부족한 곳이 몇 군데 있습니다. 예를 들어 if (x) y(); else z();(중괄호없이) 쓸 수는 있지만 try y(); finally z();.IList<T>사용하지만 의 하위 집합에 대해 동의합니다 . 당신의 다른 많은 것들은 저도 동의 할 것입니다. IReadableByIndex<out T>IAppendable<in T>
IListReader<T>) - 나는 "싱크"(쓰기 전용 인터페이스)의 반의어로 단어 "소스"를 사용합니다.
IListSource<in T>또는 IReadableList<out T>. 기본 인터페이스 유형에는 모든 파생물에 존재하지 않는 메서드가 포함되는 것이 가치가있을 수 있지만, 인터페이스를 다소 전문화하는 것이 좋은 경우가 많습니다. 예를 들어, IList<T>작동하거나 작동하지 않을 수있는 크기 조정 메소드를 포함 IResizableList<T>하는, 동일한 메소드를 구현하지만 작동을 보장하는를 가질 수 있습니다. 이러한 접근 방식은 필드가 변경 가능한 목록에 대한 유일한 현존 참조 또는 변경 불가능한 목록에 대한 공유 참조를 보유 할 수있는 경우에 유용 할 수 있습니다.
if (rl:(list as IResizableList<T>) != null) rl.Add(...);이지만 다른 제안이 있습니다. 다양한 컬렉션 및 컬렉션 어댑터의 작성자로서 저를 짜증나게하는 것은 예외를 발생시키는 많은 더미 메서드를 작성하는 것입니다. 타입 안전 팬으로서 불법적 인 방법을 호출하는 것을 허용하고 싶지 않습니다. IntelliSense 팬인 경우 나열되는 것을보고 싶지 않습니다.
한 열거 형의 값을 다른 열거 형에서 사용할 수 없다는 점이 마음에 들지 않습니다. 예를 들면 다음과 같습니다.
enum Colors { white, blue, green, red, black, yellow }
enum SpecialColors { Colors.blue, Colors.red, Colors.Yellow }
typeof(Color)! = typeof(SpecialColors).
enum SpecialColors { blue = Colors.blue, red = Colors.red, yellow = Colors.Yellow }
암시 적으로 형식화 된 변수는 IMO가 제대로 구현되지 않았습니다. Linq 표현식으로 작업 할 때만 실제로 사용해야한다는 것을 알고 있지만 로컬 범위 밖에서 선언 할 수 없다는 것은 성가신 일입니다.
MSDN에서 :
구현이 좋지 않다고 생각하는 이유는 var라고 부르지 만 변형이 되기에는 먼 길입니다. 전체 클래스 이름을 입력 할 필요가없는 간단한 구문입니다 (Linq와 함께 사용하는 경우 제외).