C#に同等のtypedefがありますか、何らかの方法で同様の動作を取得しますか?私はいくつかのグーグルをしましたが、私が見ているどこでも否定的であるようです。現在、次のような状況があります。
class GenericClass<T>
{
public event EventHandler<EventData> MyEvent;
public class EventData : EventArgs { /* snip */ }
// ... snip
}
さて、ロケット科学者は、そのイベントのハンドラーを実装しようとすると、非常に迅速に多くのタイピング(恐ろしいしゃれの謝罪)につながる可能性があることを理解する必要はありません。最終的には次のようになります。
GenericClass<int> gcInt = new GenericClass<int>;
gcInt.MyEvent += new EventHandler<GenericClass<int>.EventData>(gcInt_MyEvent);
// ...
private void gcInt_MyEvent(object sender, GenericClass<int>.EventData e)
{
throw new NotImplementedException();
}
ただし、私の場合は、intだけでなく、すでに複合型を使用していました。これを少し簡略化できたらいいですね...
編集:すなわちおそらく同様の動作を得るためにEventHandlerを再定義する必要はなく、EventHandlerを型定義します。
いいえ、typedefに相当するものはありません。 1つのファイル内で「using」ディレクティブを使用できます。
using CustomerList = System.Collections.Generic.List<Customer>;
しかし、それはそのソースファイルにのみ影響します。 CおよびC++での私の経験では、typedef
は通常、広く含まれている.hファイル内で使用されるため、プロジェクト全体で単一のtypedef
を使用できます。 C#には、あるファイルのusing
ディレクティブを別のファイルに含めることができる#include
機能がないため、この機能はC#には存在しません。
幸いなことに、doesを指定した例には修正があります-暗黙的なメソッドグループ変換。イベントサブスクリプションの行を次のように変更できます。
gcInt.MyEvent += gcInt_MyEvent;
:)
ジョンは本当に素敵なソリューションを提供しました、あなたがそれをすることができるとは知りませんでした!
時々私が頼ったのは、クラスから継承し、そのコンストラクタを作成することでした。例えば。
public class FooList : List<Foo> { ... }
(アセンブリが他の人に使用されない限り)最良の解決策ではありませんが、機能します。
実行内容がわかっている場合は、暗黙的な演算子を使用してクラスを定義し、エイリアスクラスと実際のクラスを変換できます。
class TypedefString // Example with a string "typedef"
{
private string Value = "";
public static implicit operator string(TypedefString ts)
{
return ((ts == null) ? null : ts.Value);
}
public static implicit operator TypedefString(string val)
{
return new TypedefString { Value = val };
}
}
私は実際にこれを推奨しておらず、このようなものを使用したことはありませんが、これはおそらく特定の状況で機能する可能性があります。
C#は、イベントデリゲートの継承された共分散をサポートしているため、次のようなメソッドです。
void LowestCommonHander( object sender, EventArgs e ) { ... }
イベントをサブスクライブするために使用できます。明示的なキャストは不要です
gcInt.MyEvent += LowestCommonHander;
ラムダ構文を使用することもでき、インテリセンスはすべて行われます:
gcInt.MyEvent += (sender, e) =>
{
e. //you'll get correct intellisense here
};
Typedefがないと思います。 GenericClassのジェネリックタイプではなく、特定のデリゲートタイプのみを定義できます。
public delegate GenericHandler EventHandler<EventData>
これにより短くなります。しかし、次の提案についてはどうですか:
Visual Studioを使用します。このように、入力したとき
gcInt.MyEvent +=
intellisenseからの完全なイベントハンドラシグネチャを既に提供しています。 Tabキーを押すと、そこにあります。生成されたハンドラー名を受け入れるか変更してから、もう一度Tabキーを押してハンドラースタブを自動生成します。
あなたが探しているGenericClass<int>
の振る舞いを提供する LikeType と呼ばれるオープンソースライブラリとNuGetパッケージを使用できます。
コードは次のようになります。
public class SomeInt : LikeType<int>
{
public SomeInt(int value) : base(value) { }
}
[TestClass]
public class HashSetExample
{
[TestMethod]
public void Contains_WhenInstanceAdded_ReturnsTrueWhenTestedWithDifferentInstanceHavingSameValue()
{
var myInt = new SomeInt(42);
var myIntCopy = new SomeInt(42);
var otherInt = new SomeInt(4111);
Assert.IsTrue(myInt == myIntCopy);
Assert.IsFalse(myInt.Equals(otherInt));
var mySet = new HashSet<SomeInt>();
mySet.Add(myInt);
Assert.IsTrue(mySet.Contains(myIntCopy));
}
}
ここにそのコードがあります、お楽しみください!名前空間行106http://referencesource.Microsoft.com /#mscorlib/Microsoft/win32/win32native.cs
using System;
using System.Collections.Generic;
namespace UsingStatement
{
using Typedeffed = System.Int32;
using TypeDeffed2 = List<string>;
class Program
{
static void Main(string[] args)
{
Typedeffed numericVal = 5;
Console.WriteLine(numericVal++);
TypeDeffed2 things = new TypeDeffed2 { "whatever"};
}
}
}
C++とC#の両方に、既存の型と意味的に同一のnew型を作成する簡単な方法がありません。このような「typedef」はタイプセーフプログラミングに不可欠であり、本当の恥ずかしいc#には組み込まれていません。 void f(string connectionID, string username)
とvoid f(ConID connectionID, UserName username)
の違いは明らかです...
(BOOST_STRONG_TYPEDEFのブーストを使用して、C++で同様のことを実現できます)
継承を使用したくなるかもしれませんが、それにはいくつかの大きな制限があります。
C#で同様のことを実現する唯一の方法は、新しいクラスで型を構成することです。
Class SomeType {
public void Method() { .. }
}
sealed Class SomeTypeTypeDef {
public SomeTypeTypeDef(SomeType composed) { this.Composed = composed; }
private SomeType Composed { get; }
public override string ToString() => Composed.ToString();
public override int GetHashCode() => HashCode.Combine(Composed);
public override bool Equals(object obj) => obj is TDerived o && Composed.Equals(o.Composed);
public bool Equals(SomeTypeTypeDefo) => object.Equals(this, o);
// proxy the methods we want
public void Method() => Composed.Method();
}
これは機能しますが、typedefだけでは非常に冗長です。さらに、Composedプロパティを介してクラスをシリアル化するため、シリアル化(つまりJson)に問題があります。
以下は、「Curiously Recurring Template Pattern」を使用してこれをより簡単にするヘルパークラスです。
namespace Typedef {
[JsonConverter(typeof(JsonCompositionConverter))]
public abstract class Composer<TDerived, T> : IEquatable<TDerived> where TDerived : Composer<TDerived, T> {
protected Composer(T composed) { this.Composed = composed; }
protected Composer(TDerived d) { this.Composed = d.Composed; }
protected T Composed { get; }
public override string ToString() => Composed.ToString();
public override int GetHashCode() => HashCode.Combine(Composed);
public override bool Equals(object obj) => obj is Composer<TDerived, T> o && Composed.Equals(o.Composed);
public bool Equals(TDerived o) => object.Equals(this, o);
}
class JsonCompositionConverter : JsonConverter {
static FieldInfo GetCompositorField(Type t) {
var fields = t.BaseType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy);
if (fields.Length!=1) throw new JsonSerializationException();
return fields[0];
}
public override bool CanConvert(Type t) {
var fields = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy);
return fields.Length == 1;
}
// assumes Compositor<T> has either a constructor accepting T or an empty constructor
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
while (reader.TokenType == JsonToken.Comment && reader.Read()) { };
if (reader.TokenType == JsonToken.Null) return null;
var compositorField = GetCompositorField(objectType);
var compositorType = compositorField.FieldType;
var compositorValue = serializer.Deserialize(reader, compositorType);
var ctorT = objectType.GetConstructor(new Type[] { compositorType });
if (!(ctorT is null)) return Activator.CreateInstance(objectType, compositorValue);
var ctorEmpty = objectType.GetConstructor(new Type[] { });
if (ctorEmpty is null) throw new JsonSerializationException();
var res = Activator.CreateInstance(objectType);
compositorField.SetValue(res, compositorValue);
return res;
}
public override void WriteJson(JsonWriter writer, object o, JsonSerializer serializer) {
var compositorField = GetCompositorField(o.GetType());
var value = compositorField.GetValue(o);
serializer.Serialize(writer, value);
}
}
}
Composerを使用すると、上記のクラスは単純になります。
sealed Class SomeTypeTypeDef : Composer<SomeTypeTypeDef, SomeType> {
public SomeTypeTypeDef(SomeType composed) : base(composed) {}
// proxy the methods we want
public void Method() => Composed.Method();
}
さらに、SomeTypeTypeDef
は、SomeType
と同じ方法でJsonにシリアル化されます。
メソッドをプロキシする必要があるのは面倒ですが、変装の祝福でもあります。新しいタイプであるため、選択したメソッドをfwし、新しいタイプを "typedef"に追加したいだけです。
お役に立てれば !
私がC#で見つけたtypedef
の最良の代替はusing
です。たとえば、次のコードでコンパイラフラグを介して浮動小数点の精度を制御できます。
#if REAL_T_IS_DOUBLE
using real_t = System.Double;
#else
using real_t = System.Single;
#endif
残念ながら、real_t
を使用するすべてのファイルの先頭に配置する必要があります。現在、C#でグローバル名前空間型を宣言する方法はありません。