2009-03-26 4 views
3

개체에서 인덱서를 구현하는지 여부를 어떻게 알 수 있습니까? DataRow 및 IDataReader에 대한 논리를 공유해야하지만 인터페이스를 공유하지 않습니다.인덱서 및/또는 제네릭에 대한 질문

제네릭에서도 시도했지만 where 절에 어떤 제한을 두어야하는지 알지 못합니다.

public class Indexer { 
    // myObject should be a DataRow or a IDataReader 
    private object myObject; 
    public object MyObject { 
     get { return myObject; } 
     set { myObject = value; } 
    } 
    // won't compile, myObject has no indexer 
    public object this[int index] { 
     get { return myObject[index]; } 
     set { myObject[index] = value; } 
    } 
    public Indexer(object myObject) { 
     this.myObject = myObject; 
    } 
} 

public class Caller { 
    void Call() { 
     DataRow row = null; 
     IDataReader reader = null; 
     var ind1 = new Indexer(row); 
     var ind2 = new Indexer(reader); 
     var val1 = ind1[0]; 
     var val2 = ind1[0]; 
    } 
} 

답변

5

당신은, 인덱서 속성과 인터페이스를 선언 제약으로 해당 인터페이스를 사용해야하는 것, 그리고 형식 인수 클래스는 제약 조건을 만족하기 위해 그 인터페이스를 구현해야합니다.

사용하려는 클래스를 제어하지 않으므로 작동하지 않습니다.

대안은 Indexer 클래스는 별도의 매개 변수로 GET/SET 작업을하는 것입니다 :

DataRow row = null; 
IDataReader reader = null; 
var ind1 = row.ToIndexer(); 
var ind2 = reader.ToIndexer(); 
var val1 = ind1[0]; 
var val2 = ind1[0]; 
+0

하지만 DataRow에서 내 인터페이스를 구현할 수 없습니다. –

+0

업데이트 된 답변보기. –

+0

나는 downvote하지 않았어 참고, 죄송합니다 –

1
get { 
    DataRow row = myObject as DataRow; 
    if (row != null) 
     return row[index]; 
    IDataReader reader = myObject as IDataReader; 
    if (reader != null) 
     return reader[index]; 
} 

과 같은 논리를 사용

public class Indexer { 

    private Func<int, object> getter;   
    private Action<int, object> setter; 

    public object this[int index] 
    { 
     get { return getter(index); } 
     set { setter(index, value); } 
    } 

    public Indexer(Func<int, object> g, Action<int, object> s) 
    { 
     getter = g; 
     setter = s; 
    } 
} 

public static class IndexerExtensions 
{ 
    public static Indexer ToIndexer(this DataRow row) 
    { 
     return new Indexer(n => row[n], (n, v) => row[n] = v); 
    } 

    public static Indexer ToIndexer(this IDataReader row) 
    { 
     return new Indexer(n => row[n], (n, v) => row[n] = v); 
    } 
} 

그런 다음이 작업을 수행 할 수 set {}

+0

나는 캐스팅 비용을 "키워드"로 부르고 싶지 않아서 대답이 나와 맞지 않는다. 200 개의 레코드를 가진 독자가 있다고 상상해 보라. 400 개의 캐스팅이 될 것이지만, 나는 다소 상처를 줘야한다고 생각한다. 성능 –

+0

실제로 데이터를 가져 오기 위해 데이터베이스를 방문하는 경우 400 개의 캐스트 비용이 중요하지 않을 수 있습니다. –

+0

나는 Earwicker에 동의합니다. 필자는 더 나은 유형 안전성을 제공 할 수 있기 때문에 접근 방식을 선호합니다. 아마도 완벽하게 허용 케이스,하지만 내 접근 방식 대신 IDataReader 개체를 저장할 수 있습니다. –

3

당신은 Indexer를 추상 기본 클래스로 만들 수 있습니다. tw o 하위 클래스, 하나는 DataRow, 다른 하나는 IDataReader입니다. 그들은 색인을 처리하기위한 그것의 자신의 논리, 그 유형에 대한 특정 기본 클래스를 만들 수

 
var ind1 = Indexer.CreateFromDataRow(row); 
var ind2 = Indexer.CreateFromIDataReader(reader); 

:

같은, 2 개 팩토리 메소드가 존재할 수, 쉽게 사용할 수 있도록합니다.

이렇게하면 모든 get/set 호출에 대해 유형을 지속적으로 검사하는 오버 헤드 (표준 속성 대신 단일 가상 속성 비용)를 피할 수 있습니다.