2

共通のプロパティを持ついくつかのクラスがありますが、それらを基本型から派生させることはできません (LINQ-to-SQL の制限)。

リフレクションを使用せずに、基本型があるかのように扱いたいと思います(パフォーマンスが重要です)。

例えば:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
}

public class Vehicle
{
    public int Id { get; set; }
    public string Label { get; set; }
}

この場合、Id所有しているタイプに関係なく、物件を利用できるとうれしいです。

C#でこれに似たものにする方法はありますか:

public static int GetId<T>(T entity) where T // has an int property 'Id'
{
    return entity.Id;
}

を使用できたと思いますが、プロパティを持たないオブジェクトに対してこのメ​​ソッドを使用することからコンパイル時dynamicにコードを制限する方法を探しています。Id

4

5 に答える 5

4

次のインターフェイスを使用できます。

public interface IHasId
{
    int Id { get; }
}

public class User : IHasId { ... }
public class Vehicle : IHasId { ... }

public static int GetId<T>(T entity) where T : IHasId
{
    return entity.Id;
}

ただし、クラスを変更してインターフェイスを追加できない場合は、これを行うことはできません。にプロパティが存在することを確認するコンパイル時のチェックはありませんT。リフレクションを使用する必要があります-これは遅く、明らかに理想的ではありません。

于 2013-04-04T14:57:31.980 に答える
3

共通の基本型またはインターフェイスに制約せずに、型に特定のメンバーがあることを保証する方法はありません。この制限を回避する 1 つの方法は、ラムダを使用して値にアクセスすることです。

public static int Use<T>(T value, Func<T, int> getIdFunc) { 
  int id = getIdFunc(value);
  ...
}

Use(new User(), u => u.Id);
Use(new Vehicle(), v => v.Id);
于 2013-04-04T14:58:43.833 に答える
2

共通のプロパティを使用してインターフェイスを作成し、クラスにそれを実装させることができます。

public interface IEntity
{
    int Id { get; set; }
}

public class User : IEntity
{
    public int Id { get; set; }
    public string FirstName { get; set; }
}

public class Vehicle : IEntity
{
    public int Id { get; set; }
    public string Label { get; set; }
}

public static int GetId<T>(T entity) where T : IEntity
{
    return entity.Id;
}

GetId次のように単純化できます。

public static int GetId(IEntity entity)
{
    return entity.Id;
}
于 2013-04-04T14:57:22.390 に答える
1

インターフェイスのアプローチに言及している他の回答は確かに優れていますが、Linq-to-SQL を含む状況に応じて対応を調整したいと思います。

しかし、最初に、尋ねられた質問のタイトルに対処する

基本型なしでC#制約を使用できますか?

一般的に、答えはノーです。struct具体的には、 、class、またはを制約として使用できます。new()これらは技術的には基本型ではなく、型の使用方法に関するガイダンスを提供します。これは、メソッドを特定のプロパティを持つ型に制限するという、やりたいことのレベルにはまったく達していません。そのためには、特定のインターフェイスまたは基本クラスに制約する必要があります。

特定のユースケースについては、Linq-to-SQL に言及しています。生成されたモデルから作業している場合は、生成されたモデル クラス ファイルを直接変更せずにそれらのクラスを変更するオプションが必要です。

あなたはおそらく次のようなものを持っています

// code generated by tool 
// Customer.cs
public partial class Customer // : EntityBaseClasses, interfaces, etc
{
    public int ID 
    {
        get { /* implementation */ }
        set { /* implementation */ }
    }
}

また、アカウントや注文、またはその性質のものなどの他の同様のファイル。一般的に利用可能な ID プロパティを利用したいコードを書いている場合は、 を利用しpartial2 番目partial classのクラス ファイルを定義し、これらのモデルに共通のインターフェイス タイプを導入することができます。

public interface IIdentifiableEntity
{
    int ID { get; }
}

ここでの利点は、生成されたモデルに実装が既に存在するため、簡単に使用できることです。宣言するだけで、別のファイルで宣言できます。

public partial class Customer : IIdentifiableEntity { }
public partial class Account : IIdentifiableEntity { }
// etc. 

このアプローチは、リポジトリ パターンを使用し、リポジトリGetByIdごとに同じボイラープレートを繰り返す必要のない一般的な方法を定義したい場合に、私にとって価値があることが証明されています。メソッド/クラスをインターフェイスに制約し、GetById「無料」で取得できます。

于 2013-04-04T15:26:40.753 に答える
0

必要なプロパティを持つインターフェイスを両方のクラスに実装させ、それをジェネリック制約で使用するか、タイプごとに個別のメソッドを記述する必要があります。これが、コンパイル時の安全性を確保する唯一の方法です。

于 2013-04-04T14:57:33.130 に答える